你如何在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的范围暴露给上层(作为控制器或其他任何直接访问模型的东西),而这样做需要:
- 创build一个范围,并通过您的模型中的方法公开它。 那个方法就是你公开给控制器的那个方法。
- 如果你不把你的模型暴露给你的控制器(所以你有一些服务层),那么你没事。 反腐败层是你的服务,它可以访问你的模型的范围,而不用担心如何实现范围。
关联扩展如何?
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)