Is it possible to get the ActiveRecord::Relation object for an association

17,079

Solution 1

For a few minutes I used the where(nil) hack, then I had a brainwave and tried something random:

User.first.posts.scoped

That's it! :D

Yeah, Rails + Arel is really poorly documented. Looking forward to it maturing to the point where I can actually look things up and get actual answers.

Solution 2

in Rails 4, use .scope or .spawn to access the relation object instead of the CollectionProxy. See the documentation.

Solution 3

By taking the time to actually read the Edge Guides documentation, I was able to find an answer in Section 4.3 has_many Association Reference. In short, the documentation does not shed light on whether it possible to get the ActiveRecord::Relation object or whether an ActiveRecord::Relation object is being used, but it does provide detail on how to reuse the association and tailor its result.

Section 4.3.1 Methods Added by has_many lists the collection.where as being one of the methods that is added by the has_many association. And section 4.3.1.11 collection.where(…) shows that you would use it just as you would user the where method of the query interface. More importantly, it gives a hint that objects are lazily loaded when using this method on the collection, and sure enough, an ActiveRecord::Relation object is returned.

u.posts.where("").class  # => ActiveRecord::Relation
u.posts.where("").to_sql # => SELECT `posts`.* FROM `posts` WHERE `posts`.user_id = 1 

Admittedly, not the ideal solution, but it does give me something I can chain off of.

Solution 4

In an ActiveSupport::Concern, you can't call the private method spawn or use scope or scoped.

I needed to use this.

where(true)
Share:
17,079
John
Author by

John

Updated on June 06, 2022

Comments

  • John
    John almost 2 years
    1. Do association methods, such as those defined by has_many and belongs_to utilize ActiveRecord::Relation?

    2. If so, is it possible to get the ActiveRecord::Relation object that is being used.

    We're all aware that Rails 3 is heavily using ActiveRecord::Relation objects, and Arel::Relation objects in the background, when creating queries using the Query Interface. Whenever we use the select, joins, etc. methods of the Query Interface, a ActiveRecord::Relation object is returned. However, this doesn't seem to be the case when calling an association method of a model. Instead, the query is executed immediately and an instance, or an array of instances, of the associated model is returned.

    Consider the following models:

    post.rb

    class Post < ActiveRecord::Base
      belongs_to :user
    end
    

    user.rb

    class user < ActiveRecord::Base
      has_many :posts
    end
    

    Example:

    u = User.first
    u.posts
    

    Calling u.posts returns an array of posts, not an instance of ActiveRecord::Relation. I'm wondering if it's possible to get the ActiveRecord::Relation that is being used by the association, if it is being used at all, perhaps by using Arel::Table?

    My reasoning for wanting the ActiveRecord::Relation should be obvious: It is because I want to chain off the existing association and manipulate the query to suit a different purpose.

  • John
    John over 13 years
    Love it. Much cleaner! I'm giving you the CHECKMARK. And I agree about the Arel documentation. I've been reading scraps and bits all over the place about it. It seems very powerful, but without good documentation, it can be quite annoying as well. :)
  • brittohalloran
    brittohalloran over 12 years
    is there a way to call .scoped on a custom array that I made?
  • Matchu
    Matchu over 11 years
    (The answer to that is no: scoped only makes sense on a top-level class :/)
  • Roman
    Roman almost 11 years
    Interestingly .scoped even works for has_and_belongs_to_many, which otherwise returns an Array.
  • Cyzanfar
    Cyzanfar over 7 years
    .scoped is depreciated