2

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 the 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?

Shreyas
  • 8,737
  • 7
  • 44
  • 56

2 Answers2

2

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.

Kelly
  • 40,173
  • 4
  • 42
  • 51
0
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

nvez
  • 663
  • 5
  • 9
  • Sorry @nvez, but this is not the answer I'm looking for. I'm pretty clear on what I want to accomplish, I'm just really curious as to why or how what i posted is happening. – Shreyas Mar 29 '11 at 18:02