Почему / Как метод класса доступен для массива записей только через ассоциацию в Rails 3? - PullRequest
2 голосов
/ 29 марта 2011

Рассмотрим простой пример, где у нас есть 2 модели: Article и Category.

class Article < ActiveRecord::Base
  belongs_to :category

  def self.search(title)
    where(:title => title)
  end
end

class Category < ActiveRecord::Base
  has_many :articles
end

Теперь на консоли рельсов:

Article.all.search('test article')

Как и ожидалось, возвращается ошибка

NoMethodError: undefined method `search' for #<Array:0x9aa207c>

Но когда я делаю это

Category.first.articles.search('test article')

возвращает набор записей!

Это вызывает проверку классов

 Article.all

и

Category.first.articles

оба возвращают класс Array .

Очевидно, что метод класса Article 'search' вызывается во время выполнения и выдает 'правильный' возвратзаписывает, когда к нему обращается через ассоциацию (Category), но ведет себя иначе, когда к нему обращается сам класс (Article).

Итак, что происходит?

Ответы [ 2 ]

2 голосов
/ 29 марта 2011

Это потому, что при выполнении .all запрос фактически выполняется, поэтому возвращаемый объект будет базовым массивом. Однако, когда вы выполняете Category.first, он возвращает объект Category, тогда articles фактически использует ActiveRecord::Reflection::AssociationReflection и выполняет расширение массива. Например, в rails c попробуйте:

Category.first.articles.ancestors

против

Category.first.articles.all.ancestors #throws an error

Второй выдает ошибку, потому что в этот момент объект представляет собой простой массив. Первый, однако, состоит из чего-то вроде этого:

Article(...), ActiveRecord::Base, ActiveRecord::Reflection, Object (and so on)

В качестве другого примера попробуйте это:

a = Category.first.articles; ObjectSpace.each_object(Class).select {|k| a < k }
#=> [Object, BasicObject, ActiveRecord::Base] 

Вы можете видеть, что, хотя он выглядит как массив, он наследует другие классы.

0 голосов
/ 29 марта 2011
Article.all

Возвращает массив, который выдает ошибку, как вы видели, вы пытаетесь запустить функцию класса Article для класса Array.

Я не уверен, что именно вы пытаетесь сделать, но вы могли бы сделать это, я думаю

Article.search("soem content")

Однако я не уверен, что это даст результат, так как он может просто вернуть

...