Rails ActiveRecord: подсчет ассоциаций ассоциаций - PullRequest
0 голосов
/ 11 февраля 2009

Я пытаюсь написать запрос поиска ActiveRecord безуспешно. Пожалуйста, помогите!

Эта функция моего проекта представляет собой блог с Digg-подобными функциями: каждый зарегистрированный пользователь может добавить звездочку к самому сообщению в блоге или любому из его ответов.

Итак, вот соответствующие классы моделей:

  • BlogPost (ответы has_many)
  • Ответить (принадлежит_ к сообщению блога)
  • Starring (представляет собой действие одного пользователя с одним BlogPost или Reply; он имеет полиморфный интерфейс с BlogPost и Reply, внутренне ссылаясь на них как: starrables, изобилующий полями: starrable_id и: starrable_type)

Итак, я пытаюсь написать метод в blog_post.rb, который будет возвращать общее количество звездочек для объекта BlogPost, а также для всех его классов Reply. То есть, если запись блога имеет 10 звезд, и в ней есть два ответа, каждый из которых имеет 5 звезд, он должен вернуть 20.

Как мне написать этот запрос, не совершая миллионы транзакций с базой данных?

Ответы [ 2 ]

2 голосов
/ 11 февраля 2009

Я бы предложил сделать это с помощью SQL. Вы можете сделать это несколькими способами. Вы используете MYSQL? Если вы хотите сделать с 2 запросами, а затем сложить числа вместе, вы можете сделать что-то вроде этого в SQL:

select count(starrings.id) from starrings where starrable_type='BlogPost' and starrable_id=#{blogpost.id}

и

select count(starrings.id) from starrings join replies on starrings.starrable_type='Reply' and starrable_id=replies.id and replies.blog_post_id=#{blogpost.id}

Примечание. Я не тестировал этот SQL и, возможно, что-то написал с ошибкой или сделал опечатку.

Вы можете запустить подсчет SQL с помощью 'Starring.count_by_sql (ваш sql здесь)', а затем сложить 2 числа вместе. Вероятно, вы можете свести это к 1 SQL-выражению с помощью объединения, но я бы не стал беспокоиться.

0 голосов
/ 11 февраля 2009

Предполагая, что у вас есть полиморфный метод stars как в BlogPost, так и в Reply, который возвращает объекты Starring для каждого (вы можете этого не делать, но для меня это имеет смысл), тогда в blog_post.rb вы можете сделать :

def total_number_of_stars
  stars.size + replies.inject(0) { |s,v| s.stars.size += v.stars.size }
end

По общему признанию это сделает довольно много запросов за кулисами, но это - то, как работает Rails. Если он работает недостаточно хорошо, вы можете использовать find_by_sql с заказным SQL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...