Rails: доступ к атрибутам экземпляра в методе класса отношения BelongsTo - PullRequest
1 голос
/ 10 августа 2011

Я пытаюсь перенести некоторые из моих запросов из контроллера в модель, но у меня возникают проблемы с его чистотой, как мне бы хотелось.Вот модели, с которыми я работаю:

class Post < ActiveRecord::Base
    belongs_to :account

    def self.recent_posts(account=nil)
        if account.nil? || account.tags.nil?
            results = where(:published => true).order('created_at DESC').limit(5)
        else
            results = tagged_with(account.tags).where(:published => true).order('created_at DESC').limit(5)
        end
    end
end

class Account < ActiveRecord::Base
    has_many :posts
end

Затем в контроллере я называю это как posts = account.posts.recent_posts(account).

Однако мне кажется, что должен быть какой-то способ доступа к account.tags без необходимости передавать экземпляр account в метод класса account.posts.recent_posts.Есть или я просто неправильно подхожу к этому?Спасибо!

Ответы [ 2 ]

2 голосов
/ 11 августа 2011

Первый проход для очистки это будет что-то вроде

class Post < ActiveRecord::Base
    belongs_to :account

    scope :sane_defaults, where(:published => true).order('created_at DESC').limit(5)
    scope :with_account, lambda {|account|
      if account.try(:tags)
        tagged_with(account.tags)
      end
    }
end

, а затем вызов Post.with_account(account).sane_defaults

Очень неприятно, что tagged_with не очень хорошо работает с другими областями.Большинство областей возвращают активный объект отношения, с которым вы можете связать цепочку, но, очевидно, когда передано значение nil или даже пустой массив tagged_with, возвращает хеш.Это невежливо и должно быть исправлено.

Как правило, в Ruby не проверяется nil, потому что nil - это ложное значение, а проверка на существование объекта короче и оценивает true.
Также вы можете назначить результат выражения if.так что было бы более логичным сказать:

    results = if account && account.tags
      tagged_with(account.tags).where(:published => true).order('created_at DESC').limit(5)
    else
      where(:published => true).order('created_at DESC').limit(5)
    end

Существует довольно много споров о методе try, но если у вас нет мнения о том, является ли это хорошей или плохой практикой, используйте ее, пока не разработаетеодин.Это позволит вам сократить

if account && account.tags

до

if account.try(:tags)

Было бы интересно увидеть весь ваш метод контроллера.

0 голосов
/ 10 августа 2011

Методы класса не знают конкретных экземпляров, если вы не передадите один из них в качестве ссылки.В конце концов, это совершенно разные контексты.Легко сделать метод экземпляра, который передается методу класса, как требуется:

def recent_posts
  self.class.recent_posts(self)
end

Это может выглядеть немного неловко, но это шаблон, который часто появляется, когда у вас есть служебный метод уровня класса, которыйтребуется немного информации о области действия.

Вы также можете выразить свой тест следующим образом:

if (!account || !account.tags?)
  # ...
end

Как правило, вам не нужно специально проверять nil?, если только вы неЧто касается значения, оно может быть false, что является редким случаем в подобных ситуациях.Также есть метод, введенный для текстовых полей, который может проверить, не определены ли значения одновременно и .account.tags? эквивалентно account.tags.present?, обратному account.tags.blank?

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