Hello guys,

The Salsify Engineering team made a gem to automatic eager load associations on 
rails, take a look here: 
http://blog.salsify.com/engineering/automatic-eager-loading-rails

If you want to avoid to read the entire post, they made this:

> blogs = Blogs.limit(5).to_a
# SELECT * FROM blogs LIMIT 5
 
> blogs.each { |blog| blog.posts.to_a }
# SELECT * FROM posts WHERE blog_id IN (1,2,3,4,5)

Which I think that may make a huge sense for a lot of applications.


But active record seems to not provide a hook to do overwrite internals like 
that, they had to monkey patch a lot of methods here: 
https://github.com/salsify/goldiloader/blob/master/lib/goldiloader/active_record_patches.rb

I'm not pretty comfortable with active record source code but my suggestion is 
to make a accessor or a hook to use a custom collection proxy class.


Currently when we call blog.posts we receive a 
ActiveRecord::Associations::CollectionProxy object.

What if we can change active record to use a custom builder object, or a 
lambda, like that?

ActiveRecord::Base.association_builder = lambda do |source, instance, 
association|
  SharedAssociationProxy.build(source: source, instance: instance, association: 
association)
end

class SharedAssociationProxy < ActiveRecord::Associations::CollectionProxy
  def self.build(source:, instance:, association:)
    registry[source, association] ||= new(source.klass, association)
    registry[source, association].append(instance)
  end

  def to_a(instance)
    objects.select do |object|
      object[reflection.primary_key] == object.id
    end
  end

  protected

  def objects
    @objects ||= reflection.klass.where(reflection.primary_key => 
instances.map(&:id))
  end
end

blogs = Blogs.limit(5).to_a
blogs.first.posts # will use the blogs as source since it fetched a collection
=> SharedAssociationProxy.build(source: blogs, instance: blog, association: 
:posts)

blog = Blog.first
blog.posts # will use the blog as source since it was the only fetched
=> SharedAssociationProxy.build(source: blog, instance: blog, association: 
:posts)

Like I said, I'm not pretty comfortable with active record source code, then I 
don't know the exactly details that need to be passed to the builder, lets 
focus just on the concept.

If we want a toggle option like the fully_load made by Salsify guys, we can 
just check for it on the lambda or the builder.

About the to_a method, it would be necessary to receive the model instance that 
is calling the to_a method to do the necessary work, it would happen for all 
methods that can have a custom implementation: first, last, to_a, etc.


What do you guys think about that?

Cheers,

Gabriel Sobrinho
gabrielsobrinho.com

-- 
You received this message because you are subscribed to the Google Groups "Ruby 
on Rails: Core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to rubyonrails-core+unsubscr...@googlegroups.com.
To post to this group, send email to rubyonrails-core@googlegroups.com.
Visit this group at http://groups.google.com/group/rubyonrails-core.
For more options, visit https://groups.google.com/d/optout.

Reply via email to