假设我有一个具有属性
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)
但我不知道应该过滤哪些过滤器,因为我需要首先了解用户。
你能帮我吗?
如果您想要一个数组而不是活动记录实例,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)
哇...我比预想的要长。希望其中一些有用!
试试这个:
User.where(id: 5).pluck(:id, :first_name)
它返回包含 id 和 first_name 值的数组
这也有效
User.select(:id, :first_name).find(5)
有这样的需求,但想要更通用的东西,只需从模型(包括属性)收集方法名称和值的列表。 所以,我将此方法添加到我的模型中:
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}
如果您在 2024 年遇到这个答案,另一种简洁的方法是:
User.find_by(id: 5)&.id
&
是Safe Navigation Operator,在Ruby 2.3.0(2016年发布)中引入。它允许您调用链中前一个事物的方法,而不必担心如果该方法不存在,所有事物都会崩溃。