Ruby-on-rails 从 ActiveRecord 模型获取特定属性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27037428/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 23:59:24  来源:igfitidea点击:

Get specific attributes from an ActiveRecord model

ruby-on-railsselectfilterauthorization

提问by vasilakisfil

Let's say that I have a Usermodel with attributes :id, :first_name, :last_name, and :email. In my application, guest users shouldn't see User's email and last_name. I know how to select specific values if I want a list of users but I don't know how I can get specific attributes of a specific user like

假设我有一个User带有 attributes的模型:id, :first_name, :last_name, and :email。在我的应用程序中,来宾用户不应该看到User's email and last_name. 如果我想要用户列表,我知道如何选择特定值,但我不知道如何获取特定用户的特定属性,例如

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

One solution to that is to user

对此的一种解决方案是用户

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

but then I get a hash instead of an AR record. I could do

但后来我得到了一个散列而不是 AR 记录。我可以

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

but the thing that I don't know which filters I should filter since I need to know the user first.

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

Could you help me?

你可以帮帮我吗?

回答by joshua.paling

What Choco said will work if you want an array not an active record instance. If you want an active record instance, do:

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

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

Here's some more info. I'm not sure how much you do/don't know, so I'll assume you know less rather than more.

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

I assume you realise what you're doing above is method chaining - ie, you're calling a method, then calling another method on the result of the first method. For example:

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

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

You're calling the find_by_idmethod on the Userclass. That method will return an instanceof the Userclass (ie, an active record instance). That instance has a method called attributes, which you call. The attributesmethod returns an instance of the Hashclass, representing the fields in the previous active record instance. Hashhas a slicemethod, which you call in turn. The slicemethod returns another instance of Hash, containing the subset of fields you specified.

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

So, the concept to be clear on is that when you're chaining methods, you're not calling each subsequent method on the same thing - you're calling it on the return value of the previous method in the chain.

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

OK, so with that out of the way:

好的,这样就可以了:

All the findmethods are intended to query the database and return a single instance of an Active Record model, or a plain ruby array containing multiple instances of Active Record models.

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

A lot of other methods - select, where, etc, do NOT hit the database right away, and are NOT intended to return an active record instance. They all return an instance of ActiveRecord::Relation. An ActiveRecord::Relationis kinda like a potential group of records matching certain conditions - and you can add extra conditions to it. It's like a 'database query waiting to happen', or a 'database query that may or may not have happened yet'.

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

When you call a method like where, order, or selecton ActiveRecord::Relation, it will return an instance of ActiveRecord::Relation, meaning you've got an instance of the same class, and can chain methods from that class nicely eg: User.where(name: 'Fred').select(:id, :name).order('name ASC')

当你调用的方法等whereorderselectActiveRecord::Relation,它将返回的实例ActiveRecord::Relation,这意味着你已经得到了相同的类的实例,并从该类很好例如可以链接方法:User.where(name: 'Fred').select(:id, :name).order('name ASC')

Your instance of ActiveRecord::Relationwill be very smart, and won't bother hitting the database until you call a method that clearly indicates you want the records now - such as each, all, take, etc.

你的情况ActiveRecord::Relation会很聪明,不会打扰进入数据库,直到你把那个叫清楚地表明你想要的记录,现在的方法-如eachalltake,等

So, I've gone on way longer than planned here, so I'll wrap up. Here's the code I first mentioned, with a broken down, heavily commented explanation below:

所以,我在这里的时间比计划的要长,所以我要结束了。这是我第一次提到的代码,下面有一个分解的、大量评论的解释:

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

breaking it down:

分解它:

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)

Wow... I went on longer than expected. Hope some of it was useful!

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

回答by Choco

Try this:

尝试这个:

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

it returns array containing id and first_name values

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

回答by tkhuynh

This will works as well

这也将起作用

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

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

回答by Mike State

Had a requirement like this but wanted something more generic that would just gather a list of method names and values from a model (including attributes). So, I added this method to my model:

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

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

Then, call this method with:

然后,使用以下命令调用此方法:

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

returns

回报

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