ActiveRecord includes. Specify included columns

后端 未结 6 455
野的像风
野的像风 2020-12-02 17:08

I have model Profile. Profile has_one User. User model has field email. When I call

Profile.some_scope.includes(:user)

it calls

<         


        
相关标签:
6条回答
  • 2020-12-02 17:34

    Rails doesn't have the facility to pass the options for include query. But we can pass these params with the association declaration under the model.

    For your scenario, you need to create a new association with users model under the profile model, like below

    belongs_to :user_only_fetch_email, :select => "users.id, users.email", :class_name => "User"
    

    I just created one more association but it points to User model only. So your query will be,

    Profile.includes(:user_only_fetch_email)
    

    or

    Profile.includes(:user_only_fetch_email).find(some_profile_ids)
    
    0 讨论(0)
  • 2020-12-02 17:38

    If you want to select specific attributes, you should use joins rather than includes.

    From this asciicast:

    the include option doesn’t really work with the select option as we don’t have control over how the first part of the SELECT statement is generated. If you need control over the fields in the SELECT then you should use joins over include.

    Using joins:

    Profile.some_scope.joins(:users).select("users.email")
    
    0 讨论(0)
  • 2020-12-02 17:38

    I wanted that functionality myself,so please use it. Include this method in your class

    #ACCEPTS args in string format "ASSOCIATION_NAME:COLUMN_NAME-COLUMN_NAME"

    def self.includes_with_select(*m)
        association_arr = []
        m.each do |part|
          parts = part.split(':')
          association = parts[0].to_sym
          select_columns = parts[1].split('-')
          association_macro = (self.reflect_on_association(association).macro)
          association_arr << association.to_sym
          class_name = self.reflect_on_association(association).class_name 
          self.send(association_macro, association, -> {select *select_columns}, class_name: "#{class_name.to_sym}")
        end
        self.includes(*association_arr)
      end
    

    And you will be able to call like: Contract.includes_with_select('user:id-name-status', 'confirmation:confirmed-id'), and it will select those specified columns.

    0 讨论(0)
  • 2020-12-02 17:51

    Using Mohanaj's example, you can do this:

    belongs_to :user_only_fetch_email, -> { select [:id, :email] }, :class_name => "User"
    
    0 讨论(0)
  • 2020-12-02 17:55

    You need extra belongs to in the model.

    For simple association:

    belongs_to :user_restricted, -> { select(:id, :email) }, class_name: 'User'
    

    For Polymorphic association (for example, :commentable):

    belongs_to :commentable_restricted, -> { select(:id, :title) }, polymorphic: true, foreign_type: :commentable_type, foreign_key: :commentable_id
    

    You can choose whatever belongs_to name you want. For the examples given above, you can use them like Article.featured.includes(:user_restricted), Comment.recent.includes(:commentable_restricted) etc.

    0 讨论(0)
  • 2020-12-02 17:57

    Rails does not support to select specific columns when includes. You know ,it's just lazy load.

    It use the ActiveRecord::Associations::Preloader module to load the associated data before data actually using. By the method:

    def preload(records, associations, preload_scope = nil)
        records = Array.wrap(records).compact
    
        if records.empty?
          []
        else
          records.uniq!
          Array.wrap(associations).flat_map { |association|
            preloaders_on association, records, preload_scope
          }
        end
     end
    

    preload_scope the third params of preload, is a way to select specify columns. But can't lazy load anymore.

    At Rails 5.1.6

    relation = Profile.where(id: [1,2,3])
    user_columns = {:select=>[:updated_at, :id, :name]}
    preloader = ActiveRecord::Associations::Preloader.new
    preloader.preload(relation, :user, user_columns)
    

    It will select the specify columns you passed in. But, it just for single association. You need create a patch for ActiveRecord::Associations::Preloader to support loading multiple complex associations at once.

    Here is a example for patch

    The way to use it, example

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