1

私の ActiveRecord クエリでは、select メソッドで次の情報を提供する必要があります。

(SELECT count(*) from likes where likes.spentit_id = spentits.id) as like_count,
(SELECT count(*) from comments where comments.spentit_id = spentits.id) as comment_count

もちろん、これら2つを文字列として .select() 部分に渡しますが、これを行う適切な/代替方法は何ですか?

私が呼び出そうとしている完全なクエリは次のとおりです。

SELECT DISTINCT
    spentits.*,
    username,
    (SELECT count(*) from likes where likes.spentit_id = spentits.id) as like_count,
    (SELECT count(*) from comments where comments.spentit_id = spentits.id) as comment_count,
    (SELECT count(*) from wishlist_items where wishlist_items.spentit_id = spentits.id) as wishlist_count,
    (case when likes.id is null then 0 else 1 end) as is_liked_by_me,
    (case when wishlist_items.id is null then 0 else 1 end) as is_wishlisted_by_me,
    (case when comments.id is null then 0 else 1 end) as is_commented_by_me
FROM spentits
LEFT JOIN users ON users.id = spentits.user_id
LEFT JOIN likes ON likes.user_id = 9 AND likes.spentit_id = spentits.id
LEFT JOIN wishlist_items ON wishlist_items.user_id = 9 AND wishlist_items.spentit_id = spentits.id
LEFT JOIN comments ON comments.user_id = 9 AND comments.spentit_id = spentits.id
WHERE spentits.user_id IN
    (SELECT follows.following_id
     FROM follows
     WHERE follows.follower_id = 9 AND follows.accepted = 1)
ORDER BY id DESC LIMIT 15 OFFSET 0;

ここにあるすべてのテーブルには、それぞれの ActiveRecord オブジェクトがあります。このクエリを 'activerecord'/rails の方法に変換する方法を、最小限の SQL を記述して本当に混乱させました。'9' user_id はパラメーターであると想定されます。

更新: わかりましたので、これが私が平均時間で行ったことです。生のSQLステートメントよりもはるかに優れていますが、それでも私には醜く見えます:

class Spentit < ActiveRecord::Base
  belongs_to :user
  has_many :likes
  has_many :wishlist_items
  has_many :comments

  scope :include_author_info, lambda {
    joins([:user]).
    select("username").
    select("users.photo_uri as user_photo_uri").
    select("spentits.*")
  }

  scope :include_counts, lambda {
    select("(SELECT count(*) from likes where likes.spentit_id = spentits.id) as like_count").
    select("(SELECT count(*) from comments where comments.spentit_id = spentits.id) as comment_count").
    select("(SELECT count(*) from wishlist_items where wishlist_items.spentit_id = spentits.id) as wishlist_items_count").
    select("spentits.*")
  }
end

これらのスコープ メソッドを使用して、次のことができます。

Spentit.where(:id => 7520).include_counts.include_author_info.customize_for_user(45)

クラスについて少し。AUserには がたくさんありSpentitsます。ASpentitには が多くcommentslikesとがありcommentsます。

4

1 に答える 1

0

わかりました、あなたは少し「間違ったことをしている」のです。それよりも

  scope :include_counts, lambda {
    select("(SELECT count(*) from likes where likes.spentit_id = spentits.id) as like_count").
    select("(SELECT count(*) from comments where comments.spentit_id = spentits.id) as comment_count").
    select("(SELECT count(*) from wishlist_items where wishlist_items.spentit_id = spentits.id) as wishlist_items_count").
    select("spentits.*")
  }

行う

Spentit.find(7520).likes.count
Spentit.find(7520).wishlist_items.count
Spentit.find(7520).comments.count

それ以外の

  scope :include_author_info, lambda {
    joins([:user]).
    select("username").
    select("users.photo_uri as user_photo_uri").
    select("spentits.*")
  }

行う

Spentit.find(7520).user.username
Spentit.find(7520).user.photo_uri

また、参照モデル内でスコープを定義し、それらを使用することもできます。

class Follow < ActiveRecord::Base
  belongs_to :follower, :class_name => "User"
  belongs_to :following, :class_name => "User"

  scope :accepted, lambda{ where(:accepted => 1) }
end

Spentits.where(:user => Follow.where(:follower => User.find(9)).accepted)

さて、あなたもするかもしれません:

class Spentit
  def to_hash
    hash = self.attributes
    hash[:like_count] = self.like.count
    # ...
  end
end

ただし、「通常の状況では」これらのカウントを取得するために特別なことをする必要はありません。すでにそれらを取得しています。

ただし、おそらくデフォルトのスコープの一部として作成できるように見える熱心な読み込みも実行したい場合があることに注意してください。そうしないと、必要以上に多くのクエリを実行することになります。

于 2013-06-09T23:38:50.133 に答える