你如何在Rails 3中调整ActiveRecord关联的范围?

Mar*_*rio 59 activerecord named-scope ruby-on-rails arel ruby-on-rails-3

我有一个Rails 3项目.有了Rails 3,Arel就能够重用一个范围来构建另一个范围.我想知道在定义关系时是否有办法使用范围(例如"has_many").

我有记录,其中有权限列.我想构建一个default_scope,它将我的权限列考虑在内,以便过滤记录(甚至通过关系访问的记录).

目前,在Rails 3中,default_scope(包括我发现的补丁)没有提供传递proc的可行方法(我需要后期变量绑定).是否可以定义一个可以传递命名范围的has_many?

重用命名范围的想法如下:

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

或隐式编码关系中命名范围的内容如下所示:

has_many :orders, :scope => lambda{where(:user_id => User.current_user.id)}
Run Code Online (Sandbox Code Playgroud)

我只是尝试将default_scope应用于后期绑定.我更喜欢使用Arel方法(如果有的话),但会使用任何可行的选项.

由于我指的是当前用户,因此我不能依赖于最后一刻未评估的条件,例如:

has_many :orders, :conditions => ["user_id = ?", User.current_user.id]
Run Code Online (Sandbox Code Playgroud)

Fra*_*rot 21

我建议你看看"命名的范围已经死了"

作者解释说Arel有多强大:)

我希望它会有所帮助.

编辑#1 2014年3月

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

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

  1. 创建一个范围,并通过模型中的方法公开它.那个方法就是你暴露给控制器的方法;
  2. 如果你从未将你的模型暴露给你的控制器(所以你在它们上面有某种服务层),那你就没事了.反腐败层您的服务,它可以访问您的模型范围,而无需担心范围的实现方式.

  • 确保你读到最后,因为该文章的更新#2说错误是固定的,并且_Mainly,无论你使用范围还是类方法,都会成为个人品味的问题_ (43认同)
  • 我认为此链接不再相关,因为它显示过时的信息,并建议不使用范围因为rails中的错误(已经修复) (11认同)

Pet*_* P. 20

关联扩展怎么样?

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)
Run Code Online (Sandbox Code Playgroud)

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

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

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


Kev*_*vin 15

我只是定义了类方法,而不是范围,它一直很好用

def self.age0 do
  where("blah")
end
Run Code Online (Sandbox Code Playgroud)

  • 如果由于某种原因你没有运行一个arel方法,你总是可以返回`self.scoped`以确保它们可以堆叠. (5认同)
  • @ user94154是的,返回Arel关联的类方法在功能上与范围相同. (2认同)

cra*_*aig 10

我使用类似的东西:

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


ram*_*igg 9

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