Как передать аргумент в метод делегата в Rails

Я хотел бы иметь панель инструментов для отображения сводки нескольких моделей, и я реализовал ее с помощью Presenter без собственных данных. Я использую класс ActiveModel (без таблицы данных):

class Dashboard
  attr_accessor :user_id
  def initialize(id)
    self.user_id = id
  end

  delegate :username, :password, :to => :user 
  delegate :address,  :to => :account
  delegate :friends,   :to => :friendship

end 

По делегату я хочу иметь возможность вызывать Dashboard.address и возвращать Account.find_by_user_id(Dashboard.user_id).address.

Если бы Dashboard был классом ActiveRecord, то я мог бы объявить Dashboard#belongs_to :account, и делегат работал бы автоматически (т. е. Account знал бы, что он должен вернуть атрибут адреса из аккаунта с user_id равным to user_id в экземпляре Dashboard).

Но Dashboard не является классом ActiveRecord, поэтому я не могу объявить belongs_to. Мне нужен другой способ указать учетной записи, что нужно искать нужную запись.

Есть ли способ преодолеть эту проблему? (Я знаю, что могу подделать Dashboard, чтобы иметь пустую таблицу, или я могу переписать методы экземпляра пользователя в методы класса, которые принимают аргументы. Но все эти решения — хаки).

Спасибо.


person AdamNYC    schedule 24.09.2011    source источник
comment
Это не имеет особого смысла. Что такое id? Это должно быть число? (Вы не можете send("123"), это недопустимое имя метода.) Вы не можете использовать Dashboard.user_id с attr_accessor :user_id, один из них является классом, а другой - экземпляром... Пожалуйста, поясните и приведите примеры того, как вы ожидаете, что это будет работать.   -  person Andrew Vit    schedule 24.09.2011
comment
Привет, Энди, может быть, я недостаточно ясен. Обратите внимание, что это не обычный класс ActiveRecord::Base. Поэтому мне нужен атрибут для хранения идентификатора current_user. (Хотя я не хочу сохранять этот идентификатор постоянно). С помощью делегата я хочу иметь возможность вызывать Dashboard.address и возвращать Account.find_by_user_id(Dashboard.user_id).address. Я попытался делегировать эту функцию классу Account, но мне нужно каким-то образом передать значение user_id в Account, чтобы он знал, с каким экземпляром аккаунта он должен работать.   -  person AdamNYC    schedule 24.09.2011


Ответы (1)


Когда вы пишете delegate :address, :to => :account, это создает новый метод address на Dashboard, который в основном вызывает метод account для того же объекта, а затем вызывает address для результата этого метода account. Это (очень грубо) похоже на запись:

class Dashboard
 ...
  def address
    self.account.address
  end
 ...
end

С вашим текущим классом все, что вам нужно сделать, это создать метод account, который возвращает учетную запись с правильным user_id:

class Dashboard
  attr_accessor :user_id
  def initialize(id)
    self.user_id = id
  end

  delegate :username, :password, :to => :user 
  delegate :address,  :to => :account
  delegate :friends,   :to => :friendship

  def account
    @account ||= Account.find_by_user_id(self.user_id)
  end
end

Это позволит вам получить доступ к адресу следующим образом:

dashboard = Dashboard.new(1)
# the following returns Account.find_by_user_id(1).address
address = dashboard.address
person Benoit Garret    schedule 24.09.2011
comment
Спасибо Бенуа. Это именно то, что я ищу. - person AdamNYC; 24.09.2011
comment
@AdamNYC Не стесняйтесь обращаться за разъяснениями, если у вас есть какие-либо сомнения относительно приведенного выше кода, я с удовольствием предоставлю дополнительные пояснения. - person Benoit Garret; 24.09.2011