Как получить доступ к исходной модели внутри метода ассоциации ActiveRecord - PullRequest
1 голос
/ 04 ноября 2011

Я использовал методы связывания ActiveRecord (например, в этом посте Записки Райана ), чтобы выполнить некоторые из моих более сложных ассоциаций 2-го уровня, минимизируя при этом количество запросов. Например, я использую следующую связь, чтобы получить все действия от каждого, за кем следует пользователь (follow - это модель, которая содержит только user_id и follow_user_id):

class User < ActiveRecord::Base
 <other associations, code, etc>
 has_many :follows do
 def activities(reload=false)
   @followed_activities = nil if reload
   @followed_activities ||= Activity.includes(:user, :comments, :comment_users).where(:user_id.in => self.collect {|e| e.followed_user_id}).order('activities.created_at DESC')
 end
 <.....>
end

Этот метод сработал фантастически, нареканий нет. Однако клиент попросил включить действия самого пользователя (действия follow_users + действия current_user).

Я понимаю, что это, вероятно, ruby ​​101, но я не могу понять, как получить доступ к User.id из родительской (User) модели. Как видно из кода, self ссылается на следующее отношение и возвращает список совпадающих строк из следующей таблицы.

Я вроде как заставил его работать иногда, изменив следующую строку:

@followed_activities ||= Activity.includes(:user, :comments, :comment_users).where(:user_id.in => (self.collect {|e| e.followed_user_id}) << self.first.user_id).order('activities.created_at DESC')

Однако, это а) кажется очень хакерским, и б) вызывает исключение, когда нет никаких последующих записей (что всегда имеет место с новым пользователем). Как еще я могу получить идентификатор пользователя?

1 Ответ

2 голосов
/ 04 ноября 2011

как видно в эпизоде ​​215 Asciicast , вы можете объединить два отношения, используя оператор &, поэтому что-то вроде этого должно работать:

@followed_activities    ||= Activity
                             .includes(:user, :comments, :comment_users)
                             .where(:user_id.in => (self.collect {|e| e.followed_user_id})
@current_users_activity ||= Activity
                             .includes(:user, :comments, :comment_users)
                             .where(:user_id.in => [self.first.user_id] )
@all_activities         ||= (@followed_activities & @current_users_activity).order('activities.created_at DESC')

edit:

примечание: в рельсах 3.1 оператор & устарел, вместо него используйте Relation#merge.

провел интересное исследование.Это точно не "рубин 101"!

На самом деле, self в вашем коде действительно ссылается на Ассоциативный прокси между вашим User объектом и связанными с ним Follow записями.Когда вы расширяете такую ​​ассоциацию, вы расширяете прокси-сервер (насколько я понимаю, блок равен instance_eval 'd для класса прокси).

в rails> = 3.1, есть способполучите свой идентификатор пользователя внутри своего блока (см. этот документ , раздел "расширение ассоциации"):

proxy_association.owner.id

, чтобы вы могли сделать:

class User < ActiveRecord::Base

  has_many :follows do

    def activities( reload = false )
      @followed_activities = nil if reload
      @followed_activities ||= begin
        Activity
          .includes( :user, :comments, :comment_users )
          .where( :user_id.in => [proxy_association.owner.id, *map( &:followed_user_id ) ])
          .order( 'activities.created_at DESC' )
      end
    end

  end

end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...