在Rails 4中有多个范围的has_many关系

时间:2013-06-30 15:15:18

标签: ruby-on-rails activerecord scope has-many-through

我想模拟用户和事件模型之间的这种关系。

因此我开始使用以下类:

class User < ActiveRecord::Base
...
end

class Attendance < ActiveRecord::Base
# with columns user_id and event_id
...
end

class Event < ActiveRecord::Base
  has_many :attendances
  has_many :users, :through => :attendances
  ...
end

到目前为止一切正常:我可以分配用户和访问考勤。但现在我想把国家发挥作用,这样我就可以区分,例如在“参加”,“无故缺席”,...用户之间。我的第一次尝试是:

class Event < ActiveRecord::Base
  has_many :attendances
  has_many :users, :through => :attendances
  has_many :unexcused_absent_users, -> { where :state => 'unexcused' },
                                   :through => :attendances,
                                   :source => :user
  ...
end

(:必须指定source,否则它将搜索名为'unexcused_absent_users'的属于该关联的属性) 这里的问题是,where-predicate在表'users'上进行评估。

如果没有为每个州引入新的连接表/模型,我无法如何正确地解决这个问题。特别是因为每个用户都可以在每个活动中处于一个状态,我认为使用一个出勤模型的解决方案是有道理的。

您有什么想法,如何做到这一点?

3 个答案:

答案 0 :(得分:4)

您可以简单地缩小范围以查看正确的表格:

  has_many :unexcused_absent_users, -> { where(attendances: {state: 'unexcused'}) },
                               :through => :attendances,
                               :source => :user

Evem更好,将此范围添加到Attendance模型并将其合并到:

class Attendance < ActiveRecord::Base
  def self.unexcused
    where state: 'unexcused'
  end
end

class Event < ActiveRecord::Base
  has_many :unexcused_absent_users, -> { merge(Attendance.unexcused) },
                               :through => :attendances,
                               :source => :user      
end

答案 1 :(得分:1)

我找到了一个解决方法,但我仍然认为,这很难看。

class Event < ActiveRecord::Base
  has_many :user_attendances, :class_name => 'Attendance'
  has_many :users, :through => :user_attendances, :source => :user

  has_many :unexcued_absent_user_attendances, -> { where :state => 'unexcused'}, :class_name => 'Attendance'
  has_many :unexcused_absent_users, :through => :unexcued_absent_user_attendances, :source => :user
end

一般情况下:对于我想要的每个州,我必须引入一个与范围有关的新的has_many关系,并且根据has_many-through关系。

答案 2 :(得分:1)

这对你有用吗?

class Event < ActiveRecord::Base
  has_many :attendances
  has_many :users, :through => :attendances

  def unexcused_absent_users
    User.joins(:attendances)
      .where(:state => 'unexcused')
      .where(:event_id => self.id)
  end
end  

在rails 3+方法与范围基本相同,只是不那么混乱(在我看来),它们是可链接的

event = Event.find(xxxx)
event.unexcused_absent_users.where("name LIKE ?", "Smi%")