0

と の 2 つの ActiveRecord モデルがPostありVoteます。簡単なクエリを作成したい:

SELECT *,
  (SELECT COUNT(*)
   FROM votes
   WHERE votes.id = posts.id) AS vote_count
FROM posts

activerecord DSL でそれを行う最良の方法は何だろうと思っています。私の目標は、記述しなければならない SQL の量を最小限に抑えることです。

できますPost.select("COUNT(*) from votes where votes.id = posts.id as vote_count")

これには2つの問題があります:

  1. 生の SQL。とにかくこれを DSL で書くには?
  2. これは属性のみvote_countを返し、"*" + vote_count は返しません。追加できます.select("*")が、毎回これを繰り返します。これを行うためのはるかに優れた/DRYの方法はありますか?

ありがとう

4

4 に答える 4

2

SQL の量を減らしたい場合は、そのクエリを小さな 2 つに分割して、別々に実行することができます。たとえば、投票数の部分を抽出してクエリを実行できます。

SELECT votes.id, COUNT(*) FROM votes GROUP BY votes.id;

ActiveRecord メソッドで次のように記述できます。

Vote.group(:id).count

後で使用するために結果を保存し、Post モデルから直接アクセスできます。たとえば#votes_count、メソッドとして定義できます。

class Post
  def votes_count
    @@votes_count_cache ||= Vote.group(:id).count
    @@votes_count_cache[id] || 0
  end
end

(もちろん、キャッシュを使用するたびにキャッシュの無効化または更新に関する疑問が生じますが、これはこのトピックの範囲外です。)

しかし、さらに別のアプローチを検討することを強くお勧めします。

あなたのような複雑なクエリを ActiveRecord メソッドを使用して作成すること (たとえそれが可能であったとしても) を作成したり、以前に提案したようにクエリを 2 つに分割したりすることは、どちらも悪い考えだと思います。それらは非常に雑然としたコードになり、生の SQL よりもはるかに読みにくくなります。代わりに、クエリ オブジェクトを導入することをお勧めします。IMO ナイスなインターフェイスの背後に隠れている場合、生の複雑な SQL を使用しても問題はありません。参照: M. Fowler のP of EAAおよび Brynary のCode Climate Blogへの投稿。

于 2013-11-11T11:59:46.160 に答える
0

追加の SQL をまったく使用せずにこれを行うにはどうすればよいでしょうか。Rails の counter_cache 機能の使用を検討してください。

テーブルに整数votes_count列を追加する場合、Vote の宣言を次のようにposts変更することで、Rails でそのカウンターを自動的にインクリメントおよびデクリメントすることができます。belongs_to

belongs_to :post, counter_cache: true

Rails はその後、各投稿を投票数で更新し続けます。そうすれば、カウントはすでに計算されており、サブクエリは必要ありません。

于 2013-11-08T23:09:12.150 に答える
0

おそらく、mysql ビューを作成して、それを新しい AR モデルにマップするだけです。テーブルと同様に機能します。 set_table_name "your_view_name" で指定するだけで済みます。おそらく DB レベルでは、より高速に動作し、自動的に再計算されます。

于 2013-11-10T23:19:45.597 に答える
0

Arelと ActiveRecord で Common Table Expressions のサポートを追加するpostgres_ext gemに出くわしました。これはまさにあなたが求めたものです。Gem は SQLite 用ではありませんが、一部を抽出したり、例として使用したりできます。

于 2013-12-11T20:22:36.267 に答える