3

在我的侧边栏中,我显示了新创建的用户配置文件。配置文件belongs_to用户和用户has_one_profile。我意识到我只使用了配置文件表中的 3 列,所以使用 pluck 会更好。我也有一个link_to user_path(profile.user)部分,所以我必须以某种方式告诉用户是谁。目前我正在使用includes,但我不需要整个用户表。所以我使用了来自用户和配置文件表的许多列。

我怎样才能用 pluck 优化它?我尝试了几个版本,但总是出现一些错误(大部分时间 profile.user 未定义)。

我当前的代码:

def set_sidebar_users
  @profiles_sidebar = Profile.order(created_at: :desc).includes(:user).limit(3) if user_signed_in?
end

create_table "profiles", force: :cascade do |t|
  t.integer  "user_id",      null: false
  t.string   "first_name",   null: false
  t.string   "last_name",    null: false
  t.string   "company",      null: false
  t.string   "job_title",    null: false
  t.string   "phone_number"
  t.text     "description"
  t.datetime "created_at"
  t.datetime "updated_at"
  t.string   "avatar"
  t.string   "location"
end
4

1 回答 1

7

好的,让我们解释三种不同的方式来完成你正在寻找的东西。

首先, Includesincludesjoins Includes 是有区别的,它只是急切地加载与所有指定列的关联以进行关联。它不允许您从两个表中查询或选择多个列。它joins做什么。它允许您查询两个表并选择您选择的列。

 def set_sidebar_users
  @profiles_sidebar = Profile.select("profiles.first_name,profiles.last_name,profiles.id,users.email as user_email,user_id").joins(:user).order("profile.created_at desc").limit(3) if user_signed_in?
end

它将返回包含您在子句中Profiles提供的所有列的关系。select您可以像获取配置文件对象一样获取它们e-g

@profiles_sidebar.first.user_email将为您提供此配置文件的用户电子邮件。

如果您想查询多个表或想从两个表中选择多个列,这种方法是最好的。

2.采摘

def set_sidebar_users
  @profiles_sidebar = Profile.order(created_at: :desc).includes(:user).limit(3).pluck("users.email,profiles.first_name") if user_signed_in?
end

Pluck 仅用于从多个关联中获取列,但它不允许您使用ActiveRecord. 它只是以相同的顺序返回所选列的数组。就像在第一个示例中一样,您可以使用 pluck 获取配置文件对象的用户,@profiles_sidebar.first.user 但您不能,因为它只是一个普通数组。这就是为什么您的大多数解决方案都会引发错误profile.user is not defined

  1. 与选定列的关联。

现在这是选项三。在第一个解决方案中,您可以在两个表上获取多个列并使用的功能,ActiveRecord但它不会急切加载关联。因此,如果您循环遍历返回结果的关联,它仍然会花费您 N+1 个查询,例如 @profiles_sidebar.map(&:user)

因此,如果您想使用includes但想使用选定的列,那么您应该与选定的列建立新的关联并调用该关联。例如在profile.rb

belongs_to :user_with_selected_column,select: "users.email,users.id"

现在您可以将其包含在上面的代码中

def set_sidebar_users
  @profiles_sidebar = Profile.order(created_at: :desc).includes(:user_with_selected_column).limit(3) if user_signed_in?
end

现在这将急切加载用户,但只会选择用户的电子邮件和 id。更多信息可以在 ActiveRecord 中找到。指定包含的列

更新

当您询问采摘的优点时,让我们解释一下。如您所知pluck,返回的是普通数组。所以它不会实例化 ActiveRecord 对象,它只是返回从数据库返回的数据。所以 pluck 最好在不需要 ActiveRecord 对象的地方使用,而只是以表格形式显示返回的数据。Select 返回关系,以便您可以进一步查询它或在其实例上调用模型方法。因此,如果我们总结一下,我们可以说 pluck for model 值,select for model objects

更多信息可以在http://gavinmiller.io/2013/getting-to-know-pluck-and-select/找到

于 2016-03-21T11:27:30.883 回答