#ruby-on-rails #activerecord #join
#ruby-on-rails #activerecord #Присоединиться
Вопрос:
У меня все еще возникают проблемы с созданием сложных соединений в ActiveRecord.
У меня есть пользовательская модель, которая использует плагин HasManyFriends Стива Эренберга (http://dnite.org ).
Тогда у меня есть модель UserFeedEvent, которая связывает пользователей с моделью FeedEvent.
Чего я хотел бы достичь, так это найти все события FeedEvents, связанные с друзьями пользователя.
Как я должен написать свой запрос ActiveRecord?
Вот мои модели:
class User < ActiveRecord::Base
has_many_friends
has_many :feed_events, :through => :user_feed_events, :dependent => :destroy
has_many :user_feed_events, :dependent => :destroy
end
class UserFeedEvent < ActiveRecord::Base
belongs_to :feed_event, :dependent => :destroy
belongs_to :user
end
class FeedEvent < ActiveRecord::Base
has_many :user_feed_events, :dependent => :destroy
has_many :users, :through => :user_feed_events
serialize :data
end
Заранее спасибо!
Augusto
Комментарии:
1. Почему это не просто User.feed_events ?
2. Это идеально подходит для перечисления событий подачи конкретного пользователя, вместо этого я хотел бы перечислить все события подачи всех друзей конкретного пользователя. Что-то вроде: User.friends.feed_events (но это не работает).
Ответ №1:
Копание в исходниках HasManyFriends приводит меня к мысли, что следующее должно сработать (или быть на полпути):
РЕДАКТИРОВАТЬ: обнаружено, что source
не может указывать на другую :has_many :through
ассоциацию. Итак, вы могли бы попробовать обновленную версию.
class User < ActiveRecord::Base
#...
has_many :user_feed_events_of_friends_by_me, :through => :friends_by_me,
:source => :user_feed_events
has_many :feed_events_of_friends_by_me, :through => :user_feed_events_by_me
has_many :user_feed_events_of_friends_for_me, :through => :friends_for_me,
:source => :user_feed_events
has_many :feed_events_of_friends_for_me, :through => :user_feed_events_for_me
# A wrapper to return full list of two-way friendship events
def feeds_events_of_my_friends
self.feed_events_of_friends_by_me self.feed_events_of_friends_for_me
end
end
К сожалению, HMF
плагин имеет две односторонние ссылки дружбы, что означает, что для полного списка требуется 2 запроса к БД.
Комментарии:
1. Спасибо, Лаас! Я попробовал ваше решение, но я получаю эту ошибку, и я не знаю, как ее решить: ( ActiveRecord::HasManyThroughSourceAssociationMacroError: недопустимый макрос отражения источника: has_many : through для has_many :feed_events_of_friends_by_me, :through => :friends_by_me. Используйте :source, чтобы указать отражение источника.
2. Возможно, я неправильно прочитал исходный код или он изменился со времен вашей версии (я посмотрел его на GitHub). Что вам нужно сделать, это посмотреть (например, в консоли), как называется отношение, которое указывает на друзей одним способом, а также другим способом. Затем измените код соответствующим образом.
3. Что вы подразумеваете под «именем отношения, которое указывает на друзей одним способом, а также другим способом»? В моей консоли это делает пользователь. friends_by_me работает, но использование его в вашем отношении приводит к предыдущей ошибке.
4. Более конкретно ошибка: ctiveRecord::StatementInvalid: Mysql:: Ошибка: Неизвестный столбец ‘users.user_id’ в ‘where clause’: ВЫБЕРИТЕ
user_feed_events
.* ИЗuser_feed_events
ВНУТРЕННЕГО СОЕДИНЕНИЯusers
Наuser_feed_events
.user_id =users
.id ГДЕ ((users
.user_id = 6) И ((accepted_at НЕ РАВЕН НУЛЮ)))
Ответ №2:
Я нашел работающее и более традиционное решение для SQL:
friends_id = current_user.friends.collect {|f| f.id}.join(",")
sql = "SELECT feed_events.*, user_feed_events.user_id FROM feed_events LEFT JOIN user_feed_events ON feed_events.id = user_feed_events.feed_event_id WHERE user_feed_events.user_id IN (#{friends_id}) GROUP BY feed_events.id ORDER BY feed_events.created_at DESC"
friend_feed_events = FeedEvent.paginate_by_sql(sql, :page => params[:page], :per_page => 30)
Если у вас есть более эффективный / более элегантный способ сделать то же самое, пожалуйста, дайте мне знать!
Комментарии:
1. В качестве альтернативы вы могли бы использовать,
has_many :friend_feeds, :class = > "FeedEvent", :finder_sql => ...
как показано в документации has_many , чтобы вы могли использоватьcurrent_user.friend_feeds