Ruby-on-rails 您如何确定 Rails 3 中的 ActiveRecord 关联范围?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2412340/
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 22:23:08  来源:igfitidea点击:

How do you scope ActiveRecord associations in Rails 3?

ruby-on-railsactiverecordruby-on-rails-3named-scopearel

提问by Mario

I have a Rails 3 project. With Rails 3 came Arel and the ability to reuse one scope to build another. I am wondering if there is a way to use scopes when defining a relationship (e.g. a "has_many").

我有一个 Rails 3 项目。Rails 3 带来了 Arel 以及重用一个作用域来构建另一个作用域的能力。我想知道在定义关系时是否有办法使用范围(例如“has_many”)。

I have records which have permission columns. I would like to build a default_scope that takes my permission columns into consideration so that records (even those accessed through a relationship) are filtered.

我有包含权限列的记录。我想构建一个 default_scope 来考虑我的权限列,以便过滤记录(即使是通过关系访问的记录)。

Presently, in Rails 3, default_scope (including patches I've found) don't provide a workable means of passing a proc (which I need for late variable binding). Is it possible to define a has_many into which a named scope can be passed?

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

The idea of reusing a named scope would look like:

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

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

Or implicitly coding that named scope in the relationship would look like:

或者隐式编码关系中的命名范围看起来像:

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

I'm simply trying to apply default_scope with late binding. I would prefer to use an Arel approach (if there is one), but would use any workable option.

我只是想在后期绑定中应用 default_scope。我更喜欢使用 Arel 方法(如果有的话),但会使用任何可行的选项。

Since I am referring to the current user, I cannot rely on conditions that aren't evaluated at the last possible moment, such as:

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

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

采纳答案by Franck Verrot

I suggest you take a look at "Named scopes are dead"

我建议你看看“命名范围已死”

The author explains there how powerful Arel is :)

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

I hope it'll help.

我希望它会有所帮助。

EDIT #1 March 2014

编辑 #1 三月 2014

As some comments state, the difference is now a matter of personal taste.

正如一些评论所说,现在的区别是个人品味的问题。

However, I still personally recommend to avoid exposing Arel's scope to an upper layer (being a controller or anything else that access the models directly), and doing so would require:

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

  1. Create a scope, and expose it thru a method in your model. That method would be the one you expose to the controller;
  2. If you never expose your models to your controllers (so you have some kind of service layer on top of them), then you're fine. The anti-corruption layer isyour service and it can access your model's scope without worrying too much about how scopes are implemented.
  1. 创建一个范围,并通过模型中的方法公开它。该方法将是您向控制器公开的方法;
  2. 如果您从不将模型暴露给控制器(因此您在它们之上有某种服务层),那么您没问题。反腐败层您的服务,它可以访问您模型的范围,而无需过多担心范围是如何实现的。

回答by Peter P.

How about association extensions?

关联扩展怎么样?

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)

UPDATE: I'd like to point out the advantage to association extensions as opposed to class methods or scopes is that you have access to the internals of the association proxy:

更新:我想指出关联扩展相对于类方法或作用域的优势在于您可以访问关联代理的内部结构:

proxy_association.owner returns the object that the association is a part of. proxy_association.reflection returns the reflection object that describes the association. proxy_association.target returns the associated object for belongs_to or has_one, or the collection of associated objects for has_many or has_and_belongs_to_many.

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

More details here: http://guides.rubyonrails.org/association_basics.html#association-extensions

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

回答by Kevin

Instead of scopes I've just been defining class-methods, which has been working great

我刚刚定义了类方法,而不是范围,它一直工作得很好

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

回答by craig

I use something like:

我使用类似的东西:

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

回答by ramigg

You can use mergemethod in order to merge scopes from different models. For more details search for merge in this railscast

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

回答by adamlamar

If you're just trying to get the user's orders, why don't you just use the relationship?

如果你只是想得到用户的订单,为什么不直接使用关系呢?

Presuming that the current user is accessible from the current_user method in your controller:

假设可以从控制器中的 current_user 方法访问当前用户:

@my_orders = current_user.orders

This ensures only a user's specific orders will be shown. You can also do arbitrarily nested joins to get deeper resources by using joins

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

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