Tien Yuan
Tien Yuan

Reputation: 323

Why does my new class method in a Rails model result in nil?

I'm just starting to learn rails. I have a test project and I added a instance method and a class method to a Post model class with some existing sample data.

class Post < ActiveRecord::Base
  has_many :comments

  attr_accessor :region

  def sport
    puts "Football"
  end

  def self.region
    puts "West"
  end
end

I correctly get "Football" when I run Post.first.sport

But I get nil when I run Post.first.region. Why doesn't rails console return "West"?

Thanks!

Upvotes: 2

Views: 344

Answers (3)

RubyMiner
RubyMiner

Reputation: 311

attr_accessor adds instance methods to the class.

As per your code, it creates an instance variable called "@region" during initialization of an object of Post, in the getter method.

def region
  @region
end

and default value of instance variable is 'nil'. So when you access Post.first.region, it returns the default value of the instance variable.

In 'self.region' code, its defined as class method. So it can be called using the syntax 'Model.class_method'

Thus class methods are called on class objects while instance methods are called on instance objects.

Get a deeper understanding of ruby metaclasses for a complete picture, it will make you more curious about the ruby architecture, and will help you learn more.

Upvotes: 0

Aaditi Jain
Aaditi Jain

Reputation: 7027

It fails because you are using a class method on an instance object.
Do:

Post.region #=> 'west'

When you add 'self.' to a method it becomes a class method. Class method are invoked on the entire class. Instance methods on the other hand are invoked on a instance of the class.

Use class methods when you want methods that are applicable for the entire class. For example a method like find_post_with_most_comments.

Post.find_post_with_most_comments

Use instance method when you are dealing with a particular instance of the class. For example a method like first_comment

 @post = Post.find(params[:post_id])
 @post.first_comment

Upvotes: 2

Olivier Rosset
Olivier Rosset

Reputation: 153

Since self.region is a defined as a Class method you should run Post.region to output "West"

See https://stackoverflow.com/a/11655868/1693764 for a good description of Class vs instance methods

Upvotes: 2

Related Questions