How do you scope ActiveRecord associations in Rails 3?

风格不统一 提交于 2019-12-20 08:01:34

问题


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").

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.

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?

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.

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]

回答1:


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

The author explains there how powerful Arel is :)

I hope it'll help.

EDIT #1 March 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:

  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 is your service and it can access your model's scope without worrying too much about how scopes are implemented.



回答2:


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.

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




回答3:


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

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



回答4:


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 



回答5:


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




回答6:


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:

@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

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


来源:https://stackoverflow.com/questions/2412340/how-do-you-scope-activerecord-associations-in-rails-3

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!