Rails has_many: через поиск по дополнительным атрибутам в модели объединения
Новый для Ruby и Rails, но сейчас я изучаю книгу (что, очевидно, ничего не значит, ха-ха).
У меня есть две модели: Event и User подключены через таблицу EventUser
class User < ActiveRecord::Base
has_many :event_users
has_many :events, :through => :event_users
end
class EventUser < ActiveRecord::Base
belongs_to :event
belongs_to :user
#For clarity sake, EventUser also has a boolean column "active", among others
end
class Event < ActiveRecord::Base
has_many :event_users
has_many :users, :through => :event_users
end
Этот проект представляет собой календарь, в котором я должен отслеживать людей, подписывающих и расчесывающих свое имя для данного события. Я считаю, что многие для многих - хороший подход, но я не могу сделать что-то вроде этого:
u = User.find :first
active_events = u.events.find_by_active(true)
Поскольку события фактически не имеют этих дополнительных данных, модель EventUser делает это. И хотя я мог сделать:
u = User.find :first
active_events = []
u.event_users.find_by_active(true).do |eu|
active_events << eu.event
end
Это, кажется, противоречит "пути рельсов". Может ли кто-нибудь просветить меня, это уже давно звонит мне (сегодня утром)?
Ответы
Ответ 1
Как добавить что-то подобное в свою модель пользователя?
has_many :active_events, :through => :event_users,
:class_name => "Event",
:source => :event,
:conditions => ['event_users.active = ?',true]
После этого вы сможете получать активные события для пользователя, просто позвонив:
User.first.active_events
Ответ 2
Милан Novota имеет хорошее решение, но :conditions
теперь устарел, а бит :conditions => ['event_users.active = ?',true]
просто не кажется очень рельсами. Я предпочитаю что-то вроде этого:
has_many :event_users
has_many :active_event_users, -> { where active: true }, class_name: 'EventUser'
has_many :active_events, :through => :active_event_users, class_name: 'Event', :source => :event
После этого вы все равно сможете получать активные события для пользователя, просто позвонив:
User.first.active_events
Ответ 3
Несмотря на то, что ваши u.events явно не вызывают таблицу user_events, эта таблица по-прежнему включена в SQL неявно из-за необходимых объединений. Таким образом, вы можете использовать эту таблицу в своих условиях поиска:
u.events.find(:all, :conditions => ["user_events.active = ?", true])
Конечно, если вы планируете делать этот поиск много, то уверены, дайте ему отдельную ассоциацию, как предлагает "Милан Новота", но нет необходимости в том, чтобы вы это делали.
Ответ 4
Ну, больше ответственности ставится в модель User
, чем нужно, и нет веских оснований для этого.
Мы можем сначала определить область в модели EventUser
, потому что там, где она действительно принадлежит, например:
class EventUser < ActiveRecord::Base
belongs_to :event
belongs_to :user
scope :active, -> { where(active: true) }
scope :inactive, -> { where(active: false) }
end
Теперь пользователь может иметь оба вида событий: активные события, а также неактивные события, поэтому мы можем определить отношение в модели User
следующим образом:
class User < ActiveRecord::Base
has_many :active_event_users, -> { active }, class_name: "EventUser"
has_many :inactive_event_users, -> { inactive }, class_name: "EventUser"
has_many :inactive_events, through: :inactive_event_user,
class_name: "Event",
source: :event
has_many :active_events, through: :active_event_users,
class_name: "Event",
source: :event
end
Красота в этом методе заключается в том, что функциональность активного или неактивного события принадлежит модели EventUser
, и если в будущем функциональность должна быть изменена, она будет изменена только в одном месте: EventUser
модель, и изменения будут отражены во всех других моделях.