ernie / valium

Access attribute values directly, without instantiating ActiveRecord objects.
MIT License
321 stars 11 forks source link

Support Related Models #2

Open mbleigh opened 13 years ago

mbleigh commented 13 years ago

I was going to just write a patch myself but the code is a little more involved that I expected. This would be super-amazing if you could include fields from included related models. For example, if had a Message model that belonged to a user, I'd love to be able to do something like:

messages.includes(:user)[{user: :name}, :text]

This would give me the name field from the User model and the text field from the Message model. I'd even be happy just to take SQL-style table dot notation:

messages.includes(:user)['users.name', :text]

What do you think?

ernie commented 13 years ago

At first glance, this sounds really cool!

In practice, though, I wonder how much of the speed gain will end up getting lost as the extra complexity is layered in, and I worry a bit about the complexity it adds for the user, as well.

For a simple belongs_to association, like the one you just showed, it makes some sense. For has_many associations, what would the desired behavior be? Return an array inside an array? Duplicate the columns from the parent table and return a separate row for each has_many item, to keep the array structure flat?

Since the whole intention is to avoid instantiation of the ActiveRecord objects, it seems as though at the very minimum it'd require the use of the old "includes-dependent where" (t0.r0, t1.r0, etc.) code to do joins for the associated objects.

I just wonder if your need wouldn't be better served by using the existing methods available for arrays:

people = Person.where('last_name like "Number1%"')[:id, :last_name]
widgets = Widget.where(:person_id => people.map(&:first))[:person_id, :name]
people.map! {|p| p + widgets.assoc(p.first)[1..-1]}
# or...
(people + widgets).group_by(&:first).values.map!(&:flatten).each do |id, last_name, _, name|
  puts "#{id} #{last_name} #{name}"
end

If it wouldn't, then maybe the extra overhead of ActiveRecord is justified, to handle the association logic?

mbleigh commented 13 years ago

Hmm...hadn't thought of it for anything but belongs_to relationships. That's not a bad point. At the same time, though, I think it would still save a LOT of overhead if you could do it in some fashion with joins. Imagine I have that chat example and all I'm trying to do is print out a chat log of hundreds, maybe thousands of messages. The overhead for the objects would be massive compared to the value and your solution, while certainly feasible, is a bit messy.

I can understand the challenges but if you ever figure out a relatively simple way to do it, even in a limited fashion, let me know. :)

ernie commented 13 years ago

I think you're being too kind by saying my solution is a "bit" messy. :) But yeah, it's a bit tricky to dig in and grab the AR association goodies and skip the objects without adding too much weight. Will definitely keep it in mind.