CollectionProxy vs AssociationRelation

白昼怎懂夜的黑 提交于 2020-01-29 04:33:54

问题


I am wondering about the difference between ActiveRecord::Associations::CollectionProxy and ActiveRecord::AssociationRelation.

class Vehicle < ActiveRecord::Base
  has_many :wheels
end

class Wheel < ActiveRecord::Base
  belongs_to :vehicle
end

So if I do:

v = Vehicle.new

v.wheels # => #<ActiveRecord::Associations::CollectionProxy []>

v.wheels.all # => #<ActiveRecord::AssociationRelation []>

I have no idea what is the difference between them and why this is implemented this way?


回答1:


ActiveRecord::Relation are simple query objects before being turned into a query and executed, CollectionProxy on the other hand are a little bit more sophisticated.

First of all you get association extentions, you probably saw something that looks like this, assume a book store model that has many books

class Store < ActiveRecord::Base
  has_many :books do
    def used
      where(is_used: true)
    end
  end
end

This way you get to call used books in a store using a syntax that looks like this

Store.first.books.used

But this is the most basic uses, you could use the attributes that are exposed to you in the collection proxy, which are owner, reflection and target

Owner

The owner provides a a reference to the parent object holding the association

Reflection

The reflection object is an instance of ActiveRecord::Reflection::AssocciationReflection and contains all the configuration options for the association.

Target

The target is the association collection objects (or single object when has_one and belongs_to).

Using those methods you could do some conditons in your association extention, for example if we have a blog, we give access to all deleted posts to users who are admins (lame example I know)

Class Publisher < ActiveRecord::Base
  has_many :posts do
    def deleted
      if owner.admin?
        Post.where(deleted: true)
      else
        where(deleted: true)
      end
    end
  end
end

You also get access to two more methods which are reset and reload, the first one (reset) clears the cached association objects, the second one (reload) is more common and is used to reset and then loads the associated objects from the database.

I hope this explains how having a CollectionProxy class would be so useful




回答2:


Ok. The difference is pretty simple.

Explanation based on your example:

the association proxy in v.wheels has:

  • the object in v as @owner;
  • the collection of its wheels as @target;
  • and the @reflection object represents a :has_many macro.

From docs:

Association proxies in Active Record are middlemen between the @owner and the @target. The @target object is not loaded until needed.

v = Vehicle.new
v.wheels # we are not sending any methods to @target object (collection of wheels)
# => #<ActiveRecord::Associations::CollectionProxy []>

Which means, as soon as you call any method on the @target object (that holds collection of wheels in our case) the @target is loaded, and it becomes ActiveRecord_AssociationRelation.

v.wheels.all # sending the `all` method to @target (wheels)
# => #<ActiveRecord::AssociationRelation []>


来源:https://stackoverflow.com/questions/33683555/collectionproxy-vs-associationrelation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!