Настройка моделей State и Cities Rails, ассоциаций ActiveRecord и формы

Я хотел знать, как лучше всего реализовать следующее:

  • Пользователи могут создать Post, и каждое сообщение будет связано с городом и штатом США.

  • Я хотел иметь форму, в которой есть раскрывающийся список, в котором пользователь может выбрать State и выбрать соответствующий City, например: [Голливуд] [Калифорния].

Я установил модели State и City.

Государственная модель:

# == 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

Модель города:

# == 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

С моделью Post

# == 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

С моделью Post я думал, что буду использовать ассоциацию belongs_to и has_many с настройкой ссылок/внешнего ключа, например:

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

Представление будет использовать form_for с grouped_collection для городов и collection для штатов, но я не думаю, что это хорошая реализация, потому что:

  1. Выбор city уже в качестве ассоциации с государством. Кажется излишним, когда пользователь выбирает обе модели?
  2. Выпадающий список загрузит 60000 записей городов и замедлит работу браузера.

Я хотел знать, подойдет ли ассоциация Polymorphic для моего варианта использования и может ли кто-нибудь направить меня в правильном направлении.


Мои мысли: я подумал о том, что пользователь выбирает State в раскрывающемся списке, например. Калифорния, но вводит город в text field и если город не существует в таблице Cities создает его, иначе будет ссылка на него?

Спасибо за вашу помощь.


person Wasabi Developer    schedule 27.01.2017    source источник


Ответы (1)


Вам нужна has_one through: ассоциация. Это непрямое отношение указывает рельсам присоединиться через другую ассоциацию и устраняет необходимость в дублированном внешнем ключе.

class Post < ApplicationRecord
  belongs_to :city
  has_one :state, through: :city
end

Чтобы создать полную иерархию, вы должны сделать это так:

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

Полиморфные ассоциации — совсем другое дело. Они используются, когда ассоциация может быть к разным моделям. В этом примере Comment может принадлежать Post или 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
person max    schedule 27.01.2017
comment
Что касается того, как обрабатывать фильтрацию сначала по штату, а затем по округу - это значительно более сложный вопрос, связанный с использованием ajax - вы, возможно, еще не готовы к этому. - person max; 27.01.2017
comment
Спасибо :) Я обновил и исправил опечатку. Я использую модель «Город и страна», и я видел в Spree модель «Адрес», в которой есть :country и :state, и я подумал, что это то, на что я должен взглянуть; Я почитаю, как работает has_one. - person Wasabi Developer; 27.01.2017
comment
Хорошим решением может быть использование службы геопоиска, например места Google. - person max; 27.01.2017
comment
Лучше ли создавать полную иерархию с has_one через отношения. Таким образом, в представлении вместо post.city.state в модели Post что-то вроде has_one :state, through: city позволит мне вывести post.state без добавления дополнительных методов сверху? - person Wasabi Developer; 28.01.2017
comment
Последнее означает, что вам не нужно нарушать закон Деметры — так что да, это хорошая идея. - person max; 29.01.2017