从 ActiveRecord 模型获取特定属性

问题描述 投票:0回答:5

假设我有一个具有属性

User
:id, :first_name, :last_name, and :email
模型。在我的应用程序中,访客用户不应该看到
User's email and last_name
。如果我想要用户列表,我知道如何选择特定值,但我不知道如何获取特定用户的特定属性,例如

User.find_by(id: 5).select(:id, :first_name).

一个解决方案是用户

User.find_by(id: 5).attributes.slice('id', 'first_name') 

但随后我得到的是哈希值而不是 AR 记录。我可以做

User.select(:id, :first_name).find_by(id: 1) 

但我不知道应该过滤哪些过滤器,因为我需要首先了解用户。

你能帮我吗?

ruby-on-rails select filter authorization
5个回答
135
投票

如果您想要一个数组而不是活动记录实例,Choco 所说的将起作用。如果您想要一个活动记录实例,请执行以下操作:

User.where(id: 5).select(:id, :first_name).take 

这里有更多信息。我不确定你知道/不知道多少,所以我假设你知道得更少而不是更多。

我假设您意识到上面所做的是方法链接 - 即,您正在调用一个方法,然后对第一个方法的结果调用另一个方法。例如:

User.find_by(id: 5).attributes.slice('id', 'first_name')

您正在调用

find_by_id
类上的
User
方法。该方法将返回 User 类的
instance
(即活动记录实例)。该实例有一个名为
attributes
的方法,您可以调用该方法。
attributes
方法返回
Hash
类的实例,表示前一个活动记录实例中的字段。
Hash
有一个
slice
方法,您依次调用该方法。
slice
方法返回
Hash
的另一个实例,其中包含您指定的字段子集。

因此,需要明确的概念是,当您链接方法时,您并不是在同一事物上调用每个后续方法 - 您是在链中前一个方法的返回值上调用它。

好的,那么就这样吧:

所有

find
方法都旨在查询数据库并返回 Active Record 模型的单个实例,或包含 Active Record 模型的多个实例的纯 ruby 数组。

许多其他方法 -

select
where
等,不会立即访问数据库,也不会返回活动记录实例。它们都返回一个
ActiveRecord::Relation
的实例。
ActiveRecord::Relation
有点像匹配某些条件的潜在记录组 - 您可以向其添加额外的条件。这就像“等待发生的数据库查询”,或者“可能发生也可能尚未发生的数据库查询”。

当您在

where
上调用类似
order
select
ActiveRecord::Relation
之类的方法时,它将返回
ActiveRecord::Relation
的实例,这意味着您已经获得了同一类的实例,并且可以链接方法很好地来自该班级,例如:
User.where(name: 'Fred').select(:id, :name).order('name ASC')

您的

ActiveRecord::Relation
实例将非常智能,并且不会打扰数据库,直到您调用一个明确指示您现在想要记录的方法 - 例如
each
all
take
等。

所以,我已经比计划的时间长得多了,所以我要结束了。这是我首先提到的代码,下面是详细的、经过大量注释的解释:

User.where(id: 5).select(:id, :first_name).take

分解:

my_relation = User.where(id: 5)
# The database will not have been hit yet - my_relation 
# is a query waiting to happen

my_second_relation = my_relation.select(:id, :first_name)
# The database has STILL not been hit.
# the relation now contains both the conditions 
# from the previous my_relation, and the new 'select'
# criteria we specified

my_user = my_second_relation.take
# OK, 'take' means we want the first record
# matching all our criteria,
# so my_second_relation will hit the database 
# to get it, and then return an Active Record 
# instance (ie, an instance of the User class)

哇...我比预想的要长。希望其中一些有用!


35
投票

试试这个:

User.where(id: 5).pluck(:id, :first_name) 

它返回包含 id 和 first_name 值的数组


7
投票

这也有效

User.select(:id, :first_name).find(5)


2
投票

有这样的需求,但想要更通用的东西,只需从模型(包括属性)收集方法名称和值的列表。 所以,我将此方法添加到我的模型中:

  def attributes_from_keys(*keys)
    keys.inject({}) do |hash_to_return, key|
      hash_to_return.merge(key => send(key))
    end
  end

然后,调用此方法:

MyModel.find(1).attributes_from_keys(:id, :name, :age)

退货

{id: 1, name: 'Lawrence', age: 23}

0
投票

如果您在 2024 年遇到这个答案,另一种简洁的方法是:

User.find_by(id: 5)&.id 

&
Safe Navigation Operator,在Ruby 2.3.0(2016年发布)中引入。它允许您调用链中前一个事物的方法,而不必担心如果该方法不存在,所有事物都会崩溃。

© www.soinside.com 2019 - 2024. All rights reserved.