Reputation: 3553
I wanted to know the best way to implement the following:
Users can create a Post
and each Post is associated with a US City and State.
I wanted to have a form where there is a dropdown box that a user can select the State
and select the relevant City
for example: [Hollywood] [California].
I have setup a State
and City
model.
The State model:
# == Schema Information
#
# Table name: states
#
# id :integer not null, primary key
# name :string default(""), not null
# short :string default(""), not null
# created_at :datetime not null
# updated_at :datetime not null
#
class State < ApplicationRecord
has_many :cities
end
The City model:
# == Schema Information
#
# Table name: cities
#
# id :integer not null, primary key
# name :string
# state_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_cities_on_state_id (state_id)
#
class City < ApplicationRecord
belongs_to :state
end
With the Post
model
# == Schema Information
#
# Table name: posts
#
# id :integer not null, primary key
# title :string default(""), not null
# body :string default(""), not null
class Post < ApplicationRecord
end
With the Post
model I thought I would to a belongs_to
and has_many
association with references/foreign key setup like:
class Post < ApplicationRecord
belongs_to :city
belongs_to :state
end
class City < ApplicationRecord
belongs_to :state
has_many :posts
end
class State < ApplicationRecord
has_many :cities
has_many :posts
end
The view would use a form_for
with a grouped_collection
for cities and collection
for the states but I don't think this is a good implementation because:
city
already as the association with the state. It seems redundant having the user select both model options?I wanted to know if a Polymorphic
association would fit my use case and if someone can forward me in the right direction.
My thoughts: I was thinking something where the user selects the the State
in a dropdown box eg. California, but enters the city in a text field
and if the city does not exists in Cities
table it create it, otherwise it will link to it?
Thanks for your help.
Upvotes: 0
Views: 1149
Reputation: 102250
What you want is a has_one through:
association. This indirect relation tells rails to join through another association and removes the need for a duplicated foreign key.
class Post < ApplicationRecord
belongs_to :city
has_one :state, through: :city
end
To create a full hierarchy you would do it like so:
class Post < ApplicationRecord
belongs_to :city
has_one :state, through: :city
has_one :country, through: :state
end
class City < ApplicationRecord
belongs_to :state
has_one :country, through: :state
has_many :posts
end
class State
belongs_to :country
has_many :cities
has_many :posts, through: :cities
end
class Country < ApplicationRecord
has_many :states
has_many :cities, through: :states
has_many :posts, through: :cities
end
Polymorphic associations are a very different thing altogether - its used when an association can be to different models. In this example a Comment
can be belong to a Post
or a Page
.
class Comment < ApplicationRecord
belongs_to :commentable, polymorphic: true
end
class Post < ApplicationRecord
# this tells AR to look at the `commentable` association on
# Comment.
has_many :comments, as: :commentable
end
class Page < ApplicationRecord
has_many :comments, as: :commentable
end
Upvotes: 4