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

4

20
  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.

Witness answered 14/11, 2010 at 8:21 Comment(0)
F
34

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.

Ferromagnetism answered 18/11, 2010 at 18:39 Comment(5)
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. :)Witness
is there a way to call .scoped on a custom array that I made?Brunelle
(The answer to that is no: scoped only makes sense on a top-level class :/)Ferromagnetism
Interestingly .scoped even works for has_and_belongs_to_many, which otherwise returns an Array.Frobisher
.scoped is depreciatedYogi
T
4

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

Thermidor answered 18/5, 2014 at 10:41 Comment(0)
W
1

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.

Witness answered 14/11, 2010 at 19:31 Comment(0)
J
1

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

I needed to use this.

where(true)
Johppah answered 29/1, 2016 at 20:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.