Связи моделей Rails, has_many: through и has_one с той же моделью - PullRequest
0 голосов
/ 01 декабря 2010

У меня есть две модели: пользовательская и государственная.Модель штатов имеет записи для каждого из 50 штатов США.

Я бы хотел, чтобы у каждого пользователя было два атрибута: одно "домашнее" состояние и много состояний для "посещения".

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

Вот что у меня есть, но я знаю, что должно быть что-то не так с ассоциацией has_many и has_one с одной и той же моделью.

#user.rb
class User < ActiveRecord::Base
   has_many :visits
   has_many :states, :through => :visits
   has_one :state
end

#visit.rb
class Visit < ActiveRecord::Base
   belongs_to :user
   belongs_to :state
end

#state.rb
class State < ActiveRecord::Base
   has many :visits
   has many :users, :through => :visits 
   belongs_to :user
end

Есть предложения?

Ответы [ 3 ]

1 голос
/ 28 сентября 2012

Я бы хотел, чтобы у каждого пользователя было два атрибута: одно "домашнее" состояние и много состояний для "посещения".

В ваших моделях состояние может быть только домомодин пользователь (belongs_to).

Правильная семантика будет

class User < AR::Base
  belongs_to :home_state, :class_name => "State", :foreign_key => "home_state_id", :inverse_of => :users_living
  has_and_belongs_to_many :visited_states, :through => :visits
  # ...
end

class State < AR::Base
  has_many :users_living, :class_name => "User", :inverse_of => :home_state
  # ...
end
1 голос
/ 07 июля 2014

По моему мнению, то, что у вас уже есть, является почти правильным, за исключением того, что вы сохраняете внешний ключ домашнего состояния для пользователя следующим образом:

# user.rb
class User < ActiveRecord::Base
  belongs_to :state
  has_many :visits
  has_many :states, through: visits
end

# visit.rb
class Visit < ActiveRecord::Base
  belongs_to :user
  belongs_to :state
end

# state.rb
class State < ActiveRecord::Base
  has_many :visits
  has_many :users, through: :visits
end

После этого вы получите доступ к домашнему состоянию, как показано ниже:

u = User.first
u.state

И посещенные состояния, вроде так:

u = User.first
u.states

Для ясности программирования вы можете переименовать ваши отношения:

# user.rb
class User < ActiveRecord::Base
  belongs_to :home_state, class_name: "State"
  has_many :visits
  has_many :visited_states, class_name: "State", through: visits
end

# state.rb
class State < ActiveRecord::Base
  has_many :residents, class_name: "User"
  has_many :visits
  has_many :visitors, class_name: "User", through: :visits
end

Ваша модель домена будет иметь больше смысла:

u = User.first
u.home_state
u.visited_states

s = State.first
s.residents
s.visitors

Полагаю, вы, вероятно, захотите сохранить дополнительную информацию о посещении, поэтому сохранение таблицы соединений HMT для модели Visit позволит вам сделать это, а не переходить с отношения HABTM. Затем вы можете добавить атрибуты для посещения:

# xxxxxxxxxxxxxxxx_create_visits.rb
class CreateVisits < ActiveRecord::Migration
  def change
    create_table :visits do |t|
      t.text :agenda
      t.datetime commenced_at
      t.datetime concluded_at
      t.references :state
      t.references :user
    end
  end
end
1 голос
/ 01 декабря 2010

Вы не можете иметь отношения has_many и has_one для одной модели, в данном случае это состояние. Одним из решений является:

создать статическую модель состояний, им не обязательно быть моделью базы данных, они могут быть статической переменной в модели состояний: US_STATES = {'1' => 'AK', '2' => 'AL', etc} или вы можете использовать приборы для загрузки таблицы состояний в базу данных (подробнее сложный, потому что вам нужно использовать задачу rake или задачу db: seed, чтобы загрузить приборы в базу данных, но приятно, потому что вы можете использовать активную запись для управления моделью).

тогда вы можете предоставить home_state_id для модели пользователя, которая определяет home_state, а посещения - это просто соединение между user_id и state_id.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...