How do you scope ActiveRecord associations in Rails 3?

安稳与你 提交于 2019-12-02 14:11:41

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.

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

Kevin

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

def self.age0 do
  where("blah")
end
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 

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

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