Understanding methods

Hi there, I am new to Ruby and to Rails and am having some trouble
understanding when a method has been defined or not.

My current understanding, and I am not sure if I am correct, is that
methods are defined only for a class unless inherited by subclasses
(designated by the SubClass < Class in the head of the controller
document for that Class).

So I am wondering why I keep getting a an error of undefined_method for
a method I am defining in my application controller. I have tried
bouncing it around into different controllers but I feel like it should
either be recognized in the application or in my voting controller.
This is what the method looks like:

def voted_by_user?(user)
return = false
if user
self.votes.each { |v|
return = true if user.id == v.user_id
}
end
return
end

I am trying to call this method like this:

unless @link.voted_by_user?(@current_user)
@link.votes.create(:user => @current_user)
end

I should mention that I am new to Object Oriented Programming so am
still wrapping my mind around inheritance, instance methods and class
methods. I have some background in C++ and I may be trying to think
about methods too strictly as functions, not sure.

Any help or leads on how to make sense of this would be very helpful.
Thank you.

Michael M. wrote:

Hi there, I am new to Ruby and to Rails and am having some trouble
understanding when a method has been defined or not.

My current understanding, and I am not sure if I am correct, is that
methods are defined only for a class unless inherited by subclasses

Mostly right.

(designated by the SubClass < Class in the head of the controller
document for that Class).

Controller document? What do you think you mean by that? It’s
certainly not a standard term, so I’d like to hear your definition…

So I am wondering why I keep getting a an error of undefined_method for
a method I am defining in my application controller. I have tried
bouncing it around into different controllers but I feel like it should
either be recognized in the application or in my voting controller.
This is what the method looks like:

def voted_by_user?(user)
return = false
if user
self.votes.each { |v|
return = true if user.id == v.user_id
}
end
return
end

I am trying to call this method like this:

unless @link.voted_by_user?(@current_user)
@link.votes.create(:user => @current_user)
end

Unless @link is an instance of ApplicationController (most unlikely!),
this will fail.

I should mention that I am new to Object Oriented Programming so am
still wrapping my mind around inheritance, instance methods and class
methods. I have some background in C++ and I may be trying to think
about methods too strictly as functions, not sure.

Possibly. Remember that unlike in C++, every Ruby function is a
method – that is, it belongs to an object. There is no concept of a
global function as in C++ – even something like puts is actually a
method of Object.

Any help or leads on how to make sense of this would be very helpful.
Thank you.

Reread the chapters about Ruby’s object model in the Pickaxe Book.
Repeat till understood. :slight_smile:

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Michael M. wrote:

class VotesController < ApplicationController
before_filter :login_required

def create
@link = Link.find(params[:link_id])
# make sure that the current user can’t vote for their own links
if !(@current_user.id == @link.user.id)
#user can only vote once for a link that isn’t their own
unless @link.voted_by_user?(@current_user)
@link.votes.create(:user => @current_user)
end
end
end

@link is an object of class Link so the method voted_by_user? must be
defined in app/models/link.rb which is where class Link is defined.

Is it there? From what I read your first post it seems you put it into
some controller, which is very surprising.

Paolo

Thanks for the reply Marnen.

What I meant by controller document is simply the “controller”.rb file.
Document was probably the wrong word there and I apologize for the
confusion.

@link is an instance of the votes_controller.rb file but even when I
place the voted_by_user? method in this controller, it’s still deemed
“undefined.”

I think I should pick up your suggested book up as I am having a hard
time wrapping my mind around the object model.

If you are curious, here’s my votes_controller.rb contents.

class VotesController < ApplicationController
before_filter :login_required

def create
@link = Link.find(params[:link_id])
# make sure that the current user can’t vote for their own links
if !(@current_user.id == @link.user.id)
#user can only vote once for a link that isn’t their own
unless @link.voted_by_user?(@current_user)
@link.votes.create(:user => @current_user)
end
end
end

Thank you again for your help.

Michael M. wrote:

My current understanding, and I am not sure if I am correct, is that
methods are defined only for a class unless inherited by subclasses
(designated by the SubClass < Class in the head of the controller
document for that Class).

I don’t follow you on this. I’m not sure what you mean by “the head of
the controller document for that Class.”

Take a look at this little contrived example:

http://pastie.textmate.org/private/pvwaf4z21dt0fchsvqbw

This example illustrates that a rectangle and a square share some common
behavior, but that a square is a more specific example of a rectangle.
Notice how Square overrides certain behavior inherited from Rectangle.

Also notice how Square overrides the behavior of three methods also
defined by Rectangle (width=, height=, and area). Technically, there is
no reason for Square to override Rectangle’s area method, but I did so
in the example for illustration.

In case you’re wondering Ruby allows you to define setter/getter pairs
of methods with the shortcut attr_accessor.

So I am wondering why I keep getting a an error of undefined_method for
a method I am defining in my application controller. I have tried
bouncing it around into different controllers but I feel like it should
either be recognized in the application or in my voting controller.

I am trying to call this method like this:

unless @link.voted_by_user?(@current_user)
@link.votes.create(:user => @current_user)
end

You’re saying that voted_by_user? is defined in your application
controller. So unless @link is a reference to an instance of your
ApplicationController class then “@link.voted_by_user?” will throw an
undefined method exception. The object referenced by @link, or one of
it’s superclasses must implement the method.

Michael M. wrote:

Whoah, this worked!? Now I am a bit confused and I will have to go back
and investigate why this works. I thought that the model was
responsible for setting relationships between different classes in the
database like “belongs_to” etc. I guess there’s more there than I
realized or at least there are some large gaps in my understanding.

It sounds to me like it’s the Model-View-Controller (MVC) design pattern
that’s confusing you. That’s where you need to start your research. I
would recommend you read up on MVC in general (not specific to Rails).
Once you understand that, then go back and look at how Rails implements
MVC.

@link is an object of class Link so the method voted_by_user? must be
defined in app/models/link.rb which is where class Link is defined.

Is it there? From what I read your first post it seems you put it into
some controller, which is very surprising.

Paolo

Whoah, this worked!? Now I am a bit confused and I will have to go back
and investigate why this works. I thought that the model was
responsible for setting relationships between different classes in the
database like “belongs_to” etc. I guess there’s more there than I
realized or at least there are some large gaps in my understanding.

I have been following the book “Simply Rails 2,” and I think it served
me well as a large overview but I will need to go into greater depth on
some of these relationships.

Robert W. wrote:

It sounds to me like it’s the Model-View-Controller (MVC) design pattern
that’s confusing you. That’s where you need to start your research. I
would recommend you read up on MVC in general (not specific to Rails).
Once you understand that, then go back and look at how Rails implements
MVC.

That’s a good suggestion. Thank you.

Michael M. wrote:

Robert W. wrote:

It sounds to me like it’s the Model-View-Controller (MVC) design pattern
that’s confusing you. That’s where you need to start your research. I
would recommend you read up on MVC in general (not specific to Rails).
Once you understand that, then go back and look at how Rails implements
MVC.

That’s a good suggestion. Thank you.

My suggestion would be a bit different. Put aside Rails for a few days,
and learn about Ruby’s object model itself. Once you understand that,
look at your Rails code again and understand it in light of what you’ve
learned.

Bonus tip: in Rails MVC design, Link and LinksController are completely
separate classes.

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]