web-dev-qa-db-ja.com

ActiveRecordモデルから特定の属性を取得する

属性:id, :first_name, :last_name, and :emailを持つUserモデルがあるとしましょう。私のアプリケーションでは、ゲストユーザーにはUser's email and last_nameが表示されません。ユーザーのリストが必要な場合に特定の値を選択する方法は知っていますが、特定のユーザーの特定の属性を取得する方法はわかりません

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

その解決策の1つはユーザーです

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

しかし、その後、私はARレコードの代わりにハッシュを取得します。私はそれをできた

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

しかし、最初にユーザーを知る必要があるため、どのフィルターをフィルター処理する必要があるかがわかりません。

私たちを手伝ってくれますか?

38
vasilakisfil

アクティブなレコードインスタンスではなく配列が必要な場合は、Chocoが言ったことは機能します。アクティブなレコードインスタンスが必要な場合は、以下を実行します。

_User.where(id: 5).select(:id, :first_name).take 
_

詳細はこちらをご覧ください。あなたがどれだけ知っているかわからないので、私はあなたがより多くではなくより少ない知識を仮定します。

上でやっていることはメソッドチェーンであることに気づいていると思います。つまり、メソッドを呼び出してから、最初のメソッドの結果で別のメソッドを呼び出しています。例えば:

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

Userクラスで_find_by_id_メソッドを呼び出しています。このメソッドは、Userクラス(つまり、アクティブなレコードインスタンス)のインスタンスを返します。そのインスタンスにはattributesというメソッドがあり、これを呼び出します。 attributesメソッドは、前のアクティブレコードインスタンスのフィールドを表すHashクラスのインスタンスを返します。 Hashにはsliceメソッドがあり、このメソッドを順番に呼び出します。 sliceメソッドは、指定したフィールドのサブセットを含むHashの別のインスタンスを返します。

したがって、明確にするべき概念は、メソッドをチェーンするとき、同じもので後続の各メソッドを呼び出すのではなく、チェーン内の前のメソッドの戻り値で呼び出すということです。

OK、それで邪魔にならないように:

すべてのfindメソッドは、データベースを照会し、Active Recordモデルの単一のインスタンス、またはActive Recordモデルの複数のインスタンスを含むプレーンRuby配列を返すことを目的としています。

他の多くのメソッド-selectwhereなどは、すぐにデータベースにヒットすることはなく、アクティブなレコードインスタンスを返すことを意図していません。それらはすべて_ActiveRecord::Relation_のインスタンスを返します。 _ActiveRecord::Relation_は、特定の条件に一致する可能性のあるレコードのグループのようなもので、追加の条件を追加できます。これは、「発生を待機しているデータベースクエリ」、または「まだ発生していない可能性があるデータベースクエリ」のようなものです。

_ActiveRecord::Relation_でwhereorderselectなどのメソッドを呼び出すと、_ActiveRecord::Relation_のインスタンスが返されます。つまり、同じクラスのインスタンスを取得し、そのクラスのメソッドをチェーンできます。素敵な例:User.where(name: 'Fred').select(:id, :name).order('name ASC')

_ActiveRecord::Relation_のインスタンスは非常にスマートであり、eachalltakeなど、今すぐレコードが必要であることを明確に示すメソッドを呼び出すまで、データベースにアクセスすることはありません。

それで、ここで計画していたよりもずっと長く行ったので、まとめます。以下に、最初に言及したコードを示します。詳細は、以下のコメントで詳しく説明します。

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

うわー...私は予想よりも長く行った。そのうちのいくつかが役に立つことを願っています!

95
joshua.paling

これを試して:

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

idとfirst_nameの値を含む配列を返します

24
Choco

これも同様に機能します

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

4
tkhuynh