你如何在Rails 3中使用ActiveRecord关联?

我有一个Rails 3项目。 随着Rails 3来到Arel和重用一个范围来build立另一个范围的能力。 我想知道是否有一种方法来定义关系时使用范围(例如“has_many”)。

我有logging有许可列。 我想build立一个default_scope,考虑到我的权限列,以便logging(即使是通过关系访问的)被过滤。

目前,在Rails 3中,default_scope(包括我发现的补丁)没有提供传递proc(我需要用于后期variables绑定)的可行方法。 有没有可能定义一个has_many命名的作用域可以传递给哪个?

重用命名作用域的想法如下所示:

Orders.scope :my_orders, lambda{where(:user_id => User.current_user.id)} has_many :orders, :scope => Orders.my_orders 

或者在关系中隐式编码该命名范围将如下所示:

 has_many :orders, :scope => lambda{where(:user_id => User.current_user.id)} 

我只是试图通过后期绑定来应用default_scope。 我宁愿使用Arel方法(如果有的话),但会使用任何可行的选项。

由于我指的是当前用户,我不能依赖于在最后时刻未被评估的条件,比如:

 has_many :orders, :conditions => ["user_id = ?", User.current_user.id] 

我build议你看看“命名范围已经死了”

作者在那里解释Arel有多强大:)

我希望这会有所帮助。

2014年3月编辑#1

正如一些评论所述,差异现在是个人品味的问题。

不过,我个人build议避免将Arel的范围暴露给上层(作为控制器或其他任何直接访问模型的东西),而这样做需要:

  1. 创build一个范围,并通过您的模型中的方法公开它。 那个方法就是你公开给控制器的那个方法。
  2. 如果你不把你的模型暴露给你的控制器(所以你有一些服务层),那么你没事。 反腐败层你的服务,它可以访问你的模型的范围,而不用担心如何实现范围。

关联扩展如何?

 class Item < ActiveRecord::Base has_many :orders do def for_user(user_id) where(user_id: user_id) end end end Item.first.orders.for_user(current_user) 

更新:我想指出关联扩展的优点,而不是类方法或范围是你有权访问关联代理的内部:

proxy_association.owner返回关联所属的对象。 proxy_association.reflection返回描述关联的reflection对象。 proxy_association.target返回belongs_to或has_one的关联对象,或者has_many或has_and_belongs_to_many的关联对象的集合。

更多细节在这里: http : //guides.rubyonrails.org/association_basics.html#association-extensions

而不是范围,我刚刚定义了一stream的工作方法

 def self.age0 do where("blah") end 

我使用类似于:

 class Invoice < ActiveRecord::Base scope :aged_0, lambda{ where("created_at IS NULL OR created_at < ?", Date.today + 30.days).joins(:owner) } end 

您可以使用合并方法来合并来自不同模型的范围。 有关更多详细信息,请在此railscast中search合并

如果你只是想获得用户的订单,为什么不用关系?

假定当前用户可以通过控制器中的current_user方法访问:

 @my_orders = current_user.orders 

这确保只显示用户的特定订单。 您也可以通过使用joins来进行任意嵌套连接以获取更深的资源

 current_user.orders.joins(:level1 => { :level2 => :level3 }).where('level3s.id' => X)