Rails has_many: 通过在联接模型中通过额外属性查找

Ruby 和 Rails 都是新手,但是我现在已经接受了书籍教育(这显然没什么意义,哈哈)。

我有两个模型,事件和用户通过一个表 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's 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

这似乎与“铁路方式”背道而驰。有没有人能告诉我,今晚(今天早上)这件事困扰了我很长时间?

32858 次浏览

如何添加这样的东西到您的用户模型?

has_many  :active_events, :through => :event_users,
:class_name => "Event",
:source => :event,
:conditions => ['event_users.active = ?',true]

之后,您应该能够通过调用以下命令为用户获取活动事件:

User.first.active_events

即使 u.events 不是 明确地调用 user _ events 表,但是由于必要的连接,该表仍然包含在 SQL 毫无疑问中。因此,您仍然可以在查找条件中使用该表:

u.events.find(:all, :conditions => ["user_events.active = ?", true])

当然,如果你计划做这个查找很多,那么当然,给它一个单独的协会米兰诺沃塔建议,但没有 规定为您这样做

米兰诺沃塔有一个很好的解决方案-但是 :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

那么,更多的责任是被放在 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模型,这些变化将反映在所有其他模型中。