5

Background here.

In the above link, the following example is given:

class << self
  def by_author(author)
    where(:author_id => author.id)
  end
end

Aside from that syntax being foreign to a beginner like me — I had always thought class methods were defined with def self.my_class_method — where can I find documentation about class methods in Ruby on Rails?

As far as I know, class methods are always called on the class itself (MyClass.my_class_method), but if class methods in Rails are chainable, it seems as though something else must be going on here!

Edit:

I suppose I sort of cheated by making that comment about the syntax for class methods. I'm really asking how Rails makes a class method chainable — I understand how method chaining works, but not how Rails can allow you to chain class methods without actually returning the class object itself after each "link" in the chain.

Community
  • 1
  • 1
ClosureCowboy
  • 20,825
  • 13
  • 57
  • 71

3 Answers3

5

Class methods in Ruby are really just members of the singleton class, and doing class << self involves opening the singleton class directly and adding to it, removing the need to declare it in each method definition.

This article on Ruby singletons does a good job explaining.

As far as class methods being chainable, that isn't something specific to class methods, the second method call is simply called on the object returned from the first. For example:

bar = foo.do_something.do_more

is equivalent to:

tmp = foo.do_something
bar = tmp.do_more

In Rails, this chainability is most often used for building SQL queries (e.g., with where or order, etc.). This is achieved because each of these methods returns an ActiveRecord Relation.

The reason

 foo.scoped.my_foo_class_method

works is because of ActiveRecord::Relation#method_missing doing the following:

elsif @klass.respond_to?(method)
  scoping { @klass.send(method, *args, &block) }

Which checks if the ActiveRecord class responds to the method called, and if so, calls that.

Andrew Marshall
  • 95,083
  • 20
  • 220
  • 214
  • @1AndrewMarshall +1 Thank you for the answer. I understand what would makes a method "chainable"; I don't understand how Rails takes a class method and makes ***it*** chainable. – ClosureCowboy Mar 09 '11 at 04:48
  • That leading `1` is beautiful. – ClosureCowboy Mar 09 '11 at 05:00
  • Ooohhhhhh I think I see what you mean. Are you asking why a named scope specific to an individual model is chainable with the usual `where`, `order`, etc.? (If not, please clarify a little more by editing your question with a specific example, thanks.) – Andrew Marshall Mar 09 '11 at 05:52
  • I'm actually unsure if something like `User.order.by_author` would work… though `User.by_author.order` definitely would. – Andrew Marshall Mar 09 '11 at 05:57
  • It does. My best guess is that it uses Ruby's fantastic [`method_missing`](http://ruby-doc.org/core-1.8.7/classes/Kernel.html#M001069) to look for the method in the model class, but I'd have to dive into the code to be sure. – Andrew Marshall Mar 09 '11 at 06:01
  • @AndrewMarshall Yes, that's exactly what I'm wondering. I've updated the question. And your theory might be exactly it. – ClosureCowboy Mar 09 '11 at 14:53
  • I was right, see [`ActiveRecord::Relation#method_missing`](https://github.com/rails/rails/blob/master/activerecord/lib/active_record/relation.rb#L393). It checks if the model class responds to the method, and if so, calls that. – Andrew Marshall Mar 09 '11 at 17:34
4

Having class << self is also another way to define your methods so that you do not have to call "def self.my_method" or "def MyClass.my_method" for every single method that you are defining as a class method. Instead of calling

  def self.my_method1
  end

  def self.my_method2
  end
class << self
  def my_method1
  end

  def my_method2
  end
end

Cheers!

RubyFanatic
  • 2,241
  • 3
  • 22
  • 35
2

The following two bits of code are equivalent.

Using self.method:

class Hello
  def self.world
    puts "Hello, World!"
  end
end

Using class << self:

class Hello
  class << self
    def world
      puts "Hello, World!"
    end
  end
end

The only difference is readability, as well as the ease in refactoring. The class << self technique is often used when metaprogramming.

There is another thread that explains this. class << self vs self.method with Ruby: what's better?

Community
  • 1
  • 1