I have the following models:
class Property < ApplicationRecord
# Other validations
has_one :address
accepts_nested_attributes_for :address, update_only: true
end
class Address < ApplicationRecord
has_one :country
has_one :state
has_one :city
has_one :suburb
belongs_to :property
end
The relationships for country
, state
, city
and suburb
are all linked with a has_many
and belongs_to
between each other.
On my properties/_form.html.erb
file I'm trying to create the address with nested fields_for
the :address
and on those nested fields using options_from_collection_for_select
. Code below:
<fieldset>
<div class="form-group">
<%= form.label :address, "Dirección", class: "col-sm-2 control-label"%>
<div class="col-sm-9">
<%= form.fields_for :address do |ff| %>
<div class="row">
<div class="col-sm-4">
<select class="form-control" name="property[address_attributes][country_id]" >
<%= options_from_collection_for_select(Country.all, :id, :name) %>
</select>
</div>
<div class="col-sm-4">
<select class="form-control" name="property[address_attributes][state_id]" >
<%= options_from_collection_for_select(State.all, :id, :name) %>
</select>
</div>
<div class="col-sm-4">
<select class="form-control" name="property[address_attributes][city_id]" >
<%= options_from_collection_for_select(City.all, :id, :name) %>
</select>
And getting this error on submit:
So I've changed my form a bit with this:
<%= ff.select :country, options_from_collection_for_select(Country.all, :id, :name) %>
On all of my relationships and now the error I get is:
Country(#70194352893700) expected, got "1" which is an instance of String(#70194311847460)
Here is the code on my schema.rb
describing my addresses
table:
create_table "addresses", force: :cascade do |t|
t.string "street"
t.integer "number"
t.integer "zip_code"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "property_id"
t.integer "countries_id"
t.integer "states_id"
t.integer "cities_id"
t.integer "suburbs_id"
t.index ["cities_id"], name: "index_addresses_on_cities_id"
t.index ["countries_id"], name: "index_addresses_on_countries_id"
t.index ["property_id"], name: "index_addresses_on_property_id"
t.index ["states_id"], name: "index_addresses_on_states_id"
t.index ["suburbs_id"], name: "index_addresses_on_suburbs_id"
end
I'd guess that your address
table doesn't have a country_id
field on it even though your Address
model says that there should be a relationship.
You can verify by looking at db/schema.rb
.
If the address
table is missing that column you can do something like this on the command line to add it:
rails g migration add_country_id_to_addresses country:belongs_to
And then run rake db:migrate
.
There's a little bit of "magic" involved in the instructions above, so here's an explanation.
rails g migration
is telling Rails to generate a database migration.
add_country_to_addresses
is the name of the migration. You could also use AddCountryToAddresses
if you're into CamelCase over snake_case. If rails finds _to_*
(or To*
) at the end of your migration name it can infer the name of the table to generate the migration for. In this case the addresses
table.
country:belongs_to
tells Rails that the migration should link the addresses
table to the countries
table. It will add a country_id
column and (depending on your db settings) will generate an index and/or foreign key for the new column.
Your db/schema.rb
shows that you do not, in fact, have a country_id
field on that table. You have a countries_id
field.
To fix this you can generate a blank migration:
rails g migration rename_countries_id_on_addresses
And then edit the migration to contain:
change_table :addresses do |t|
t.rename :countries_id, :country_id
end
And then run migrations:
rake db:migrate
You can find more info about changing tables with migrations here: https://guides.rubyonrails.org/active_record_migrations.html#changing-tables