How will ActiveRelation affect rails' includes() 's capabilities?
Asked Answered
M

3

7

I've looked over the Arel sources, and some of the activerecord sources for Rails 3.0, but I can't seem to glean a good answer for myself as to whether Arel will be changing our ability to use includes(), when constructing queries, for the better.

There are instances when one might want to modify the conditions on an activerecord :include query in 2.3.5 and before, for the association records which would be returned. But as far as I know, this is not programmatically tenable for all :include queries:

(I know some AR-find-includes make t#{n}.c#{m} renames for all the attributes, and one could conceivably add conditions to these queries to limit the joined sets' results; but others do n_joins + 1 number of queries over the id sets iteratively, and I'm not sure how one might hack AR to edit these iterated queries.)

Will Arel allow us to construct ActiveRecord queries which specify the resulting associated model objects when using includes()?

Ex:

User :has_many posts( has_many :comments)

User.all(:include => :posts) #say I wanted the post objects to have their 
 #comment counts loaded without adding a comment_count column to `posts`.

#At the post level, one could do so by: 
posts_with_counts = Post.all(:select => 'posts.*, count(comments.id) as comment_count', 
         :joins => 'left outer join comments on comments.post_id = posts.id',
         :group_by => 'posts.id') #i believe

#But it seems impossible to do so while linking these post objects to each 
  #user as well, without running User.all() and then zippering the objects into 
  #some other collection (ugly) 
  #OR running posts.group_by(&:user) (even uglier, with the n user queries)
Maseru answered 20/5, 2010 at 1:33 Comment(1)
Steven Xu effectively asked my question in it's more base form. #4909378Maseru
M
3

ActiveRecord::Relation is a fairly weak wrapper around Base#find_by_sql, so :include queries are not extended in any way by its inclusion.

Maseru answered 31/5, 2010 at 19:25 Comment(1)
Which reduces the question to: #4909378Maseru
B
4

Why don't you actually use AREL at its core. Once you get down to the actual table scope you can use Arel::Relation which is COMPLETELY different from ActiveRecord implementation itself. I truly believe that the ActiveRecord::Relation is a COMPLETELY different (and busted) implementation of a wrapper around an Arel::Relation & Arel::Table. I choose to use Arel at its core by either doing Thing.scoped.table (Arel::Table) which is the active record style OR Arel::Table.new(:table_name) which gives me a fresh Arel::Table (my preferred method). From this you can do the following.

posts = Arel::Table.new(:thing, :as => 'p') #derived relation
comments = Arel::Table.new(:comments, :as => 'c') # derived relation
posts_and_comments = posts.join(comments).on( posts[:id].eq(:comments[:id]) )

# now you can iterate through the derived relation by doing the following
posts_and_comments.each {...} # this will actually return Arel::Rows which is another story.  
#

An Arel::Row returns a TRUE definition of a tuple from the set which will consist of an Arel::Header (set of Arel::Attributes) and a tuple.

Also slightly more verbose, the reason why I use Arel at its core is because it truly exposes the relational model to me which is the power behind ActiveRelation. I have noticed that ActiveRecord is exposing like 20% of what Arel has to offer and I am affraid that developers will not realize this NOR will they understand the true core of Relational Algebra. Using the conditions hash is to me "old school" and an ActiveRecord style programming in a Relational Algebra world. Once we learn to break away from the Martin Fowler model based approach and adopt the E.F. Codd Relational Model based approach this is actually what RDBMS have been trying to do for decades but gotten very wrong.

I've taken the liberty to start a seven part learning series on Arel and Relational Algebra for the ruby community. These will consist of short videos ranging from absolute beginner to advanced techniques like self referencing relations and closure under composition. The first video is at http://Innovative-Studios.com/#pilot Please let me know if you need more information or this was not descriptive enough for you.

The future looks bright with Arel.

Buttonhook answered 20/5, 2010 at 22:24 Comment(3)
Thank you for mentioning ActiveRecord::Relation. That comment led me here: metautonomo.us/2010/05/11/activerecord-relation-vs-arel which brings me one step closer to understanding the wrapper system.Maseru
"Why don't you actually use AREL at it's core." Because I'd like to use formtastic, so the designers I work with can edit forms the way they want to. I'm not ready to abandon ActiveRecord yet.Maseru
I don't believe this matters; the answer, I mean. I'm in complete agreement that using arel directly is almost mandatory for more advanced queries, but it's not doing the same thing as using the traditional includes with ActiveRelation, from what I can tell.Miscreated
M
3

ActiveRecord::Relation is a fairly weak wrapper around Base#find_by_sql, so :include queries are not extended in any way by its inclusion.

Maseru answered 31/5, 2010 at 19:25 Comment(1)
Which reduces the question to: #4909378Maseru
I
1

Isn't

Post.includes([:author, :comments]).where(['comments.approved = ?', true]).all

what you're looking for? (taken from the official docs)

Isochronous answered 6/2, 2011 at 21:12 Comment(3)
Pardon, I must not have been clear. What I was asking for is to modify the members loaded in the target of the includes'd association. For instance, to get a count of the number of comments for each post without loading the comment objects from the db.Maseru
I haven't tested your example, but I believe that query would also reduce the set of posts to just those which had a comment which was marked approved, as well.Maseru
Let me know how I can edit the question to make this all more obvious.Maseru

© 2022 - 2024 — McMap. All rights reserved.