ActiveRecord包括。 指定包含的列

我有模特简介。 个人资料has_one用户。 用户模型有现场电子邮件。 我打电话的时候

Profile.some_scope.includes(:user) 

它叫

 SELECT users.* FROM users WHERE users.id IN (some ids) 

但我的用户模型有许多字段,我没有在渲染中使用。 是否可以仅加载用户的电子邮件? 所以,SQL应该是这样的

 SELECT users.email FROM users WHERE users.id IN (some ids) 

Rails没有设施来传递包含查询的选项。 但我们可以通过模型下的关联声明传递这些参数。

对于您的场景,您需要在配置文件模型下创建与用户模型的新关联,如下所示

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

只是我创建了一个关联,但它只指向用户模型。 所以你查询将是,

 Profile.includes(:user_only_fetch_email) 

要么

 Profile.includes(:user_only_fetch_email).find(some_profile_ids) 

如果要选择特定属性,则应使用joins而不是includes

从这个asciicast :

include选项实际上不适用于select选项,因为我们无法控制如何生成SELECT语句的第一部分。 如果您需要控制SELECT中的字段,那么您应该使用include而不是include。

使用joins

 Profile.some_scope.joins(:users).select("users.email") 

你需要在模型中额外属于。

对于简单的关联:

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

对于多态关联(例如, :commentable ):

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

您可以选择所需的belongs_to名称。 对于上面给出的示例,您可以使用它们,如Article.featured.includes(:user_restricted)Comment.recent.includes(:commentable_restricted)等。

我自己想要这个function,所以请使用它。 在您的课程中包含此方法

#ACCEPTS args采用字符串格式“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 

您可以调用如下: Contract.includes_with_select('user:id-name-status', 'confirmation:confirmed-id') ,它将选择那些指定的列。

使用Mohanaj的例子,你可以这样做:

 belongs_to :user_only_fetch_email, -> { select [:id, :email] }, :class_name => "User" 

Rails不支持在includes时选择特定列。 你知道,这只是lazy load

它使用ActiveRecord :: Associations :: Preloader模块在数据实际使用之前加载相关数据。 通过该方法 :

 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 preload的第三个参数,是一种选择指定列的方法。 但是不能再懒了

在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) 

它将选择您传入的指定列。但是,它仅用于单个关联。 您需要为ActiveRecord::Associations::Preloader创建一个补丁,以支持一次加载多个复杂关联。

这是补丁的一个例子

使用它的方式,例如