В таком домене:
class User
has_many :posts
has_many :topics, :through => :posts
end
class Post
belongs_to :user
belongs_to :topic
end
class Topic
has_many :posts
end
Я могу прочитать все идентификаторы темы через user.topic_ids
, но я не вижу способа применить условия фильтрации к этому методу, так как он возвращает Array
вместо ActiveRecord::Relation
.
Проблема заключается в том, что при заданном Пользователе и существующем наборе Тем помечаются те, для которых есть сообщения пользователя. В настоящее время я делаю что-то вроде этого:
def mark_topics_with_post(user, topics)
# only returns the ids of the topics for which this user has a post
topic_ids = user.topic_ids
topics.each {|t| t[:has_post]=topic_ids.include(t.id)}
end
Но это загружает все идентификаторы темы независимо от входного набора. В идеале я хотел бы сделать что-то вроде
def mark_topics_with_post(user, topics)
# only returns the topics where user has a post within the subset of interest
topic_ids = user.topic_ids.where(:id=>topics.map(&:id))
topics.each {|t| t[:has_post]=topic_ids.include(t.id)}
end
Но единственное, что я могу сделать конкретно, это
def mark_topics_with_post(user, topics)
# needlessly create Post objects only to unwrap them later
topic_ids = user.posts.where(:topic_id=>topics.map(&:id)).select(:topic_id).map(&:topic_id)
topics.each {|t| t[:has_post]=topic_ids.include(t.id)}
end
Есть ли способ лучше? Возможно ли иметь что-то вроде select_values
в ассоциации или области видимости? FWIW, я на рельсах 3.0.x, но мне было бы интересно узнать и о 3.1.
Зачем я это делаю?
По сути, у меня есть страница результатов для полусложного поиска (который происходит только на основе данных темы), и я хочу пометить результаты (темы) как материалы, с которыми взаимодействовал пользователь (написал сообщение).
Так что да, есть еще один вариант, который будет выполнять объединение [Тема, сообщение], чтобы результаты выходили как отмеченные или нет из поиска, но это лишит меня возможности кэшировать запрос темы (запрос, даже без присоединиться, дороже, чем получение только идентификаторов для пользователя)
Обратите внимание, что описанные выше подходы действительно работают, просто они кажутся неоптимальными.