How to eager load associations with the current_user?

前端 未结 4 753
暖寄归人
暖寄归人 2021-02-07 05:33

I\'m using Devise for authentication in my Rails app. I\'d like to eager load some of a users associated models in some of my controllers. Something like this:

c         


        
相关标签:
4条回答
  • 2021-02-07 05:50

    I ran into the same issue and although everyone keeps saying there's no need to do this, I found that there is, just like you. So this works for me:

    # in application_controller.rb:
    def current_user
      @current_user ||= super && User.includes(:saved_listings).find(@current_user.id)
    end
    

    Note that this will load the associations in all controllers. For my use case, that's exactly what I need. If you really want it only in some controllers, you'll have to tweak this some more.

    This will also call User.find twice, but with query caching that shouldn't be a problem, and since it prevents a number of additional DB hits, it still is a performance gain.

    0 讨论(0)
  • 2021-02-07 05:52

    Why not do it with default_scope on the model?

    like so:

    Class User  < ActiveRecord::Base
      ...
      default_scope includes(:saved_listings)
      ...
    end
    
    0 讨论(0)
  • 2021-02-07 05:55

    Override serialize_from_session in your User model.

    class User
      devise :database_authenticatable
    
      def self.serialize_from_session key, salt
        record = where(id: key).eager_load(:saved_listings, roles: :accounts).first
        record if record && record.authenticatable_salt == salt
      end
    end
    

    This will however, eager load on all requests.

    0 讨论(0)
  • 2021-02-07 06:13

    I wanted to add what I think is a better solution. As noted in comments, existing solutions may hit your DB twice with the find request. Instead, we can use ActiveRecord::Associations::Preloader to leverage Rails' work around loading associations:

    def current_user
      @current_user ||= super.tap do |user|
        ::ActiveRecord::Associations::Preloader.new.preload(user, :saved_listings)
      end
    end
    

    This will re-use the existing model in memory instead of joining and querying the entire table again.

    0 讨论(0)
提交回复
热议问题