开发者

How do you fix the n+1 queries problem in ActiveRecord (Rails 3) when also using the after_initialize callback?

开发者 https://www.devze.com 2023-03-16 17:42 出处:网络
Model: class Project < ActiveRecord::Base has_many :user_roles after_initialize :add_user_roles def add_user_roles

Model:

class Project < ActiveRecord::Base
  has_many :user_roles 
  after_initialize :add_user_roles

  def add_user_roles
    UserRoles.all.each do |ur|
      self.user_roles << ur unless self.user_roles.include?(ur)
    end
  end
end

Statement that finds the projects:

@projects = Project.includes(:user_roles)

So you can see, I'm telling it to include the user roles association in the query. However, I'm still seeing the n+1 queries problem: it finds the roles once for each project.

If I remove the usage of self.user_roles from the callback and look at the logs, I can see it finds the projects and their user roles in 2 queries - one for the projects, and one for the roles using project_id in (1,2,3,4,5...,n).

Is there a way to work around this?

Let me clarify a bit: While I'm willing to work around my specific situation if req开发者_如何学Pythonuired, I'd much prefer answers that focused on how to fix the problem in general. I am capable of writing a kludge to get the data in the state that I want it without using the after_initialize callback, and hence not coming into the n+1 queries problem. However, I would rather not do that, so I prefer answers to the general problem as opposed to my specific example.


take a look at rails eager loading http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations

you can load association while loading object using includes

User.find(2).includes(:assets)#will load all assets with user

or you can specify in model to eager load association

app/models/user.rb

class User< AR::Base
   has_many :posts,:include=>:comments
end

class Post < AR::Base
  has_many :comments
  belongs_to :user
end

now u.posts will load comments for each post


Even eager-loaded associations aren't available in after_initialize (they get loaded after the record is initialized). See this Rails issue for some discussion:

https://github.com/rails/rails/issues/13156

Related to the original question: it looks like every project will have the same set of UserRole objects. I'm guessing there's a has_many :through that's been sanitized out, but even so, how does a Project ever wind up not having the full set? I'm not seeing how Project and UserRole are actually connected here - from what's visible in the example, this:

class Project < ActiveRecord::Base
  def user_roles
    UserRole.all
  end
end

would accomplish the same thing as the after_initialize...


This is likely caused by the after_initialize callback, which is run every time each of the objects are initialized. If the point of the callback is to automatically assign every role to every user (unless already assigned), then you could do this via a before_save filter instead. That way, the code won't run when doing your Project.includes(:user_roles) finder.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号