У меня проблема с оптимизацией SQL-запроса и использование активной записи для создания запроса. он включает в себя выбор идентификатора и счетчика ассоциации, а также условное соединение с переменным входом. Кроме того, я havent смог использовать оператор where, потому что мне нужны результаты, у которых пока нет ассоциаций. Мои модели являютсяАктивная запись, SQL: выбор и подсчет связи с условием объединения
class Vote < ActiveRecord::Base
belongs_to :user
belongs_to :venue
belongs_to :catering_event
validates :catering_event_id, uniqueness: { scope: :user_id }
end
class Venue < ActiveRecord::Base
has_many :votes
has_many :catering_events, through: :votes
has_many :users, through: :votes
end
class CateringEvent < ActiveRecord::Base
has_many :votes
has_many :venues, through: :votes
has_many :users, through: :votes
end
То, что я есть места, catering_events (события для краткости), и пользователи. пользователи могут набирать 1 голос за событие, где голосование является пользователем, выбирая место для мероприятия (user_id, place_id и catering_event_id).
На странице события шоу я хочу отобразить все места проведения и их подсчет голосов, в которых места без голосования подсчитывают количество голосов 0, которое я пытаюсь выполнить с помощью одного запроса. Я не мог использовать предложение where, потому что мои попытки отфильтровывали места, которые еще не голосовали.
В настоящее время у меня есть два функциональных решения, оба из которых я неудовлетворен. первый - это прямой запрос find_by_sql; однако я должен полу-взломать возвращаемые значения, потому что find_by_sql возвращает только атрибуты, которые имеет в настоящее время модель.
Для моих текущих данных:
#<Vote:0x007fb9f681ac38 id: 1, user_id: 2, venue_id: 3, catering_event_id: 1>,
#<Vote:0x007fb9f681aa58 id: 2, user_id: 1, venue_id: 2, catering_event_id: 1>,
#<Vote:0x007fb9f681a8f0 id: 3, user_id: 1, venue_id: 1, catering_event_id: 2>
Моего функциональный find_by_sql запрос:
sql =
"SELECT COUNT(votes.id) AS id, venues.id AS venue_id
FROM venues
LEFT OUTER JOIN votes ON votes.venue_id = venues.id
AND votes.catering_event_id = ?
LEFT OUTER JOIN catering_events ON catering_events.id = votes.catering_event_id
GROUP BY venues.id"
=> "SELECT COUNT(votes.id) AS id, venues.id AS venue_id FROM venues LEFT OUTER JOIN votes ON votes.venue_id = venues.id AND votes.catering_event_id = ? LEFT OUTER JOIN catering_events ON catering_events.id = votes.catering_event_id GROUP BY venues.id"
pry(main)> Vote.find_by_sql [sql, '1']
Vote Load (9.0ms) SELECT COUNT(votes.id) AS id, venues.id AS venue_id FROM venues LEFT OUTER JOIN votes ON votes.venue_id = venues.id AND votes.catering_event_id = '1' LEFT OUTER JOIN catering_events ON catering_events.id = votes.catering_event_id GROUP BY venues.id
=> [
#<Vote:0x007fb9f33ca8c0 id: 0, venue_id: 1>,
#<Vote:0x007fb9f33ca668 id: 1, venue_id: 2>,
#<Vote:0x007fb9f33ca258 id: 1, venue_id: 3>
]
это возвращает все места и их votecounts для события питания 1. Однако, я должен назвать vote_count как некоторые атрибут на модели, из которой я вызываю find_by_sql, а так как голосование имеет 3 условия, нет модели 1, к которой я могу добавить атрибут votecount. когда я пытаюсь пространство имен счетчика для настраиваемого поля, я не получаю @attributes есть, как говорят документы, он просто опускает значение:
Vote Load (0.7ms) SELECT COUNT(votes.id) AS vote_count, venues.id AS venue_id
FROM venues
LEFT OUTER JOIN votes ON votes.venue_id = venues.id
AND votes.catering_event_id = '1'
LEFT OUTER JOIN catering_events ON catering_events.id = votes.catering_event_id
GROUP BY venues.id
=> [
#<Vote:0x007fb9f31d29a0 id: nil, venue_id: 1>,
#<Vote:0x007fb9f31d2248 id: nil, venue_id: 2>,
#<Vote:0x007fb9f31d1c58 id: nil, venue_id: 3>
]
Второе решением я Нагуляв предполагает использование активной записи в сделать запрос, однако я гавань выяснили, как правильно дезинфицировать стыки заявление с переменной catering_event_id: (я не на самом деле запустить это на новых линиях, но для удобства чтения я разделить его)
Venue.select('venues.id as venue_id')
.joins('LEFT OUTER JOIN votes ON votes.venue_id = venues.id AND votes.catering_event_id = 2')
.joins('LEFT OUTER JOIN catering_events ON catering_events.id = votes.catering_event_id').group('venues.id')
.count('votes.id')
(0.6ms) SELECT COUNT(votes.id) AS count_votes_id, venues.id AS venues_id FROM `venues` LEFT OUTER JOIN votes ON votes.venue_id = venues.id AND votes.catering_event_id = 2 LEFT OUTER JOIN catering_events ON catering_events.id = votes.catering_event_id GROUP BY venues.id
=> {1=>1, 2=>0, 3=>0}
Обратите внимание на первую joins statement, мне пришлось жестко кодировать 2 в:
AND votes.catering_event_id = 2
as i havnt выяснил, как передать переменную в активную запись о соединениях.
В целом, я пытаюсь выполнить один запрос, используя либо прямой sql с помощью find_by_sql, либо активную запись (мои предпочтения относятся к активной записи), для выбора всех мест проведения и их подсчета голосов для переменной catering_event. Я бы предпочел изменить одно из моих текущих решений, чтобы либо позволить find_by_sql возвращать настраиваемые атрибуты с именами, либо определять, как правильно передать оператор объединения интерполированную/дезинфицированную переменную.
я на Rails 4.2.1 и 2.2.0 рубин