Why/How is a class method accessible to an array of records only through an association in Rails 3?
Consider a simple example, where we have 2 models, Article and 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
Now, on the rails console :
Article.all.search('test article')
As expected returns an error
NoMethodError: undefined method `search' for #<Array:0x9aa207c>
But when I do this
Category.first.articles.search('test article')
returns a set of records!
This prompts a check on t开发者_高级运维he classes of
Article.all
and
Category.first.articles
both returning the Array class.
Obviously, Article's class method 'search' is being inducted in run time and prompting a 'correct' return of records when accessed through its association (Category) but behaving otherwise when accessed by the class itself (Article).
So, What's happening?
This is because when you perform .all
the query is actually executed, so the object returned will be a basic array. However, when you perform Category.first
, it will return a Category object, then articles
is actually making use of ActiveRecord::Reflection::AssociationReflection
and doing an extension of an Array. For example, in rails c
try:
Category.first.articles.ancestors
vs
Category.first.articles.all.ancestors #throws an error
The second one throws an error, because at this point the object is just a simple Array. The first, however, is made up of something like this:
Article(...), ActiveRecord::Base, ActiveRecord::Reflection, Object (and so on)
As another example, try this:
a = Category.first.articles; ObjectSpace.each_object(Class).select {|k| a < k }
#=> [Object, BasicObject, ActiveRecord::Base]
You can see that although it looks like an Array, it's inheriting those other classes.
Article.all
This returns an array that's giving you the error as you saw, you're trying to run a class function of Article
on the Array
class.
I'm not sure what exactly you're trying to accomplish but you could do this, I think
Article.search("soem content")
However, I'm not sure if that would return a result, as it might just return an
精彩评论