Ruby-on-rails Rails has_many :通过连接模型中的额外属性查找

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/408872/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 20:52:29  来源:igfitidea点击:

Rails has_many :through Find by Extra Attributes in Join Model

ruby-on-railsrubyhas-manyhas-many-through

提问by Stefan Mai

New to both Ruby and Rails but I'm book educated by now (which apparently means nothing, haha).

Ruby 和 Rails 的新手,但我现在已经受过书本教育(这显然没有任何意义,哈哈)。

I've got two models, Event and User joined through a table EventUser

我有两个模型, 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'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

This project is a calendar, in which I have to keep track of people signing up and scratching their name out for a given event. I figure the many to many is a good approach, but I can't do something like this:

这个项目是一个日历,我必须在其中跟踪人们注册并为给定事件刮掉他们的名字。我认为多对多是一个很好的方法,但我不能做这样的事情:

u = User.find :first
active_events = u.events.find_by_active(true)

Because events don't actually HAVE that extra data, the EventUser model does. And while I could do:

因为事件实际上没有额外的数据,所以 EventUser 模型有。虽然我可以这样做:

u = User.find :first
active_events = []
u.event_users.find_by_active(true).do |eu|
  active_events << eu.event
end

This seems to be contrary to "the rails way". Can anyone enlighten me, this has been bugging me for a long time tonight (this morning)?

这似乎与“轨道方式”相反。谁能启发我,今晚(今天早上)这一直困扰着我很长时间?

回答by Milan Novota

How about adding something like this into your User model?

将这样的东西添加到你的用户模型中怎么样?

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

After that you should be able to get active events for a user just by calling:

之后,您应该能够通过调用来获取用户的活动事件:

User.first.active_events

回答by msanteler

Milan Novota has a good solution – but :conditionsis now deprecated and the :conditions => ['event_users.active = ?',true]bit just doesn't seem very rails anyways. I prefer something like this:

Milan 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

After that you should still be able to get active events for a user just by calling:

之后,您应该仍然可以通过调用以下方法为用户获取活动事件:

User.first.active_events

回答by Gareth

Even though your u.events isn't explicitlycalling the user_events table, that table is still included in the SQL implicitlybecause of the necessary joins. So, you can still use that table in your find conditions:

即使您的 u.events 没有显式调用 user_events 表,由于必要的连接,该表仍隐式包含在 SQL 中。因此,您仍然可以在查找条件中使用该表:

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

Of course, if you plan to be doing this lookup a lot then sure, give it a separate association as Milan Novota suggests, but there's no requirementfor you to do it that way

当然,如果你计划,以确保这样的查找了很多话,给它一个独立的关联作为米兰Novota建议,但没有要求为你这样做的

回答by Arslan Ali

Well, more responsibility is being put in Usermodel than actually needed, and there is no good reason to do so.

好吧,User模型中的责任比实际需要的要多,而且没有充分的理由这样做。

We can first define the scope in EventUsermodel because where it actually belongs, like:

我们可以首先在EventUser模型中定义范围,因为它实际上属于哪里,例如:

class EventUser < ActiveRecord::Base
  belongs_to :event
  belongs_to :user

  scope :active,   -> { where(active: true)  }
  scope :inactive, -> { where(active: false) } 
end

Now, a user could have both kind of events: active events as well as inactive events, so we can define the relationship in Usermodel as follows:

现在,用户可以同时拥有两种事件:活动事件和非活动事件,因此我们可以在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

The beauty in this technique is that the functionality of being an active or an inactive event belongs to EventUsermodel, and if in future the functionality needs to be modified, it would be modified only in one place: EventUsermodel, and the changes will be reflected in all other models.

这种技术的美妙之处在于活动或非活动事件的功能属于EventUser模型,如果将来需要修改该功能,则只在一个地方进行修改:EventUser模型,更改将反映在所有其他型号。