Подключение друзей к другим моделям

#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