私のアプリには、いくつかの計算を実行するgoal_ytd
メソッドを持つUser
モデルがあります。
コントローラーには、User
またはusers
の@users
の変数ActiveRecord::Relation
があり、@users
のgoal_ytd
sをすべて合計したいと思います。
私の最初の傾向は:
@users.sum(&:goal_ytd)
ActiveRecord::Relation
でsum
を使用することは、Rails 4.1。
そこで、コードを次のように変更しました。
@users.to_a.sum(&:goal_ytd)
次に、NoMethodError
をスローしました。これは、特定の状況では、@users
が@users = User
によって割り当てられ、User
にはto_a
メソッドがないためです。
@users
を使用して@users = User.all
を割り当てると、Relation#all
も非推奨になるため、非推奨の警告がスローされます。
すべてのUsers
を配列として取得する方法はありますか?もっと良い方法はありますか?
オンRails 4.1
goal_ydt
がusersテーブルの列の場合:
@users.sum(:goal_ydt)
goal_ydt
がUser
クラスのメソッドの場合:
@users.to_a.sum(&:goal_ydt)
map
とsum
の組み合わせを使用するのが好きです
@users.map(&:goal_ydt).sum
ここでは、列挙可能なメソッドを使用しないでください。 ActiveRecord :: Relationshipで定義され、パラメータとしてシンボルを受け取るsum
を使用します。主な違いは、データベースでSUM
クエリを実行するため、dbからすべてのレコードをプルするよりもはるかに高速であるということです。また、レコードのいずれかで特定のフィールドの値が空白の場合、列挙可能なsum
はエラーをスローしますが、ActiveRecordのエラーはスローしません。要するに:
@users.sum(:goal_ydt)
編集:
ただし、goal_ydt
はフィールドではなくメソッドであり、モデルをループする以外に選択肢はありません。私が通常これを行う方法は、scoped
メソッドを使用することです。
@users.scoped.sum(&:goal_ydt)
ここでの問題は、Relation#all
の非推奨に関する根本的な誤解に根ざしています。 Relation#all
は非推奨ですが、Model#all
は非推奨です。したがって:
@users = User.all
まだ完全に有効ですが、
@users = User.where(first_name: "Mike").all
は非推奨です。
したがって、最終的なソリューションは次のようになります。
@users = User.all
unless current_user.admin?
@users = @users.where(company_id: current_user.company_id)
end
@users.to_a.sum(&:goal_ytd)
新しい質問は次のようになります。すべてのユーザーの目標を、すべてをメモリにロードせずに、できれば1行で合計するにはどうすればよいですか。それはまた別の日だと思います。