#ruby-on-rails #activerecord
#ruby-on-rails #activerecord
Вопрос:
Я ищу наиболее подходящий для Rails способ получения отдельного списка категорий для доступных песен на данном альбоме.
Вот оно в SQL для album_id = 1
-- Using subselects
select * from categories where id in (
select distinct category_id
from categorizations
where song_id in (select song_id from album_songs
where album_id = 1 and available = 't')
)
order by name asc;
-- Using joins
select distinct c.* from categories c
inner join categorizations cz on c.id = cz.category_id
left join album_songs a on cz.song_id = a.song_id
where a.album_id = 1 and a.available = 't'
order by c.name asc;
Мои рабочие (хотя и наивные!) попытки перенести это в ActiveRecord
## attempting to do it like subselects (although they're not really
## subselects, it executes them individually -- from what i've read
## ActiveRecord won't do subselects?)
Category.where('id IN (?)',
Categorization.select('DISTINCT category_id').where('song_id IN (?)',
Album.find(1).songs.available.map(amp;:song_id)
).map(amp;:category_id)
).order('name ASC')
## joins - although at this point it's pretty much all sql
## as i couldn't find a way to do the left join in pure AR
## i'm also duplicating my AlbumSongs.available scope -- is
## that scope reusable here? (outside the AlbumSongs model?)
Category.select('DISTINCT categories.*')
.joins(:categorizations,
'LEFT OUTER JOIN album_songs ON categorizations.song_id = album_songs.song_id')
.where('album_songs.album_id = ? and available', 1)
Я собираюсь использовать последний вариант, но, похоже, я мог бы просто написать его на SQL?
Есть ли какой-либо способ улучшить это, чтобы оно больше соответствовало Rails?
Ответ №1:
Что ж, это, безусловно, помогло бы, если бы вы опубликовали настройки своей модели. Но предполагая, что:
* песня имеет множество : категорий, :через => категоризации
* в альбоме не так много песен
Почему бы просто не сделать:
Album.includes({:songs => {:categorizations => :categories}}).find(1).songs.collect {|s| s.category}.flatten.uniq