开发者

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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜