Ruby on Rails Sunday, July 31, 2011

Filippos wrote in post #1013927:
> Studying the RoR 3 Tutorial book by Michael Hartl
> and on page 345 there's the code inside the SessionsHelper:
>
> _________________________________________________________
> module SessionsHelper
>
> def sign_in(user)
> cookies.permanent.signed[:remember_token] = [user.id, user.sault]
> self.current_user = user
> end
>
> end
> __________________________________________________________
>
> What is the purpose of "self" inside the session helper?
> I know that inside a model it refers to the class object.
> For example
>
> Class User < ActiveRecord::Base
> self.salt
>
> it refers to User.salt
>
> But when it is inside a helper, does it refer to the helper itself?

Remember that no code inside a method actually executes until the method
is called. When the signin method is actually called by some object,
for instance:

some_object.sign_in(userA)

...then inside the sign_in() method, self is equal to the object that
called the sign_in method, which in this case is some_object.

However, the book never talks about what object is calling the various
methods. Instead, you have a controller like this:


class SessionsController < ApplicationController

def new
end

def create
end

def destroy
end

end

and the book talks about some url getting mapped to the new action,
which then causes rails to execute the file new.html.erb (and then rails
sends the resulting new.html file back to the browser). But if you know
any ruby, then you can infer that rails has to create a
SessionsController object, like this:

sess_controller = SessionsController.new

in order to be able to call the new, create, and destroy methods, e.g.

sess_controller.new

That part of the book confused me, too, because instead of this:

def sign_in
...
self.current_user = user
end

you could also write:

def sign_in

@current_user = user
end

but you definitely cannot write:

def sign_in
..
current_user = user
end

That creates a 'local variable' called current_user which will be
destroyed when the sign_in method finishes executing. '@' variables
persist as long as the sess_controller object still exists.

The way this code works:

def sign_in
...
self.current_user = user
end

is the self is the object calling the sign_in method. What object is
calling the sign_in method? That is a bit convoluted. The sign_in
method is in a module called SessionsHelpers, and you have this code in
a file:

class ApplicationController < ActionController::Base
protect_from_forgery
include SessionsHelper
end

That means all the methods in SessionsHelper become methods in the
ApplicationController class. But you also have this file:

class SessionsController < ApplicationController
def new
end

def create
end

def destroy
end

end


..so through inheritance all the ApplicationController methods become
methods of SessionsController--including the SessionsHelper methods. In
the end, that means a SessionsController object, e.g.

sess_controller = SessionsController.new

is the object that is going to be calling the sign_in method, and so
inside the sign_in method self is going to be equal to sess_controller.
Of course, rails calls sign_up behind the scenes, so what object is
calling sign_up isn't obvious, and therefore determining what self is
inside the sign_up method isn't obvious.

Now the question is why use self in the sign_in method here:

def sign_in
...
self.current_user = user
end

when you can avoid all that confusing stuff and just write:

def sign_in

@current_user = user
end


The short answer: it's good practice to always use an accessor method to
access an instance variable--rather than assign directly to an instance
variable. The reason is that if, for instance, you want to apply some
kind of transformation to a value before assigning it to an instance
variable, you can do that in the current_user=() method rather than
hunting through your code and looking for every @current_user = ... line
and making the change to each of those lines.

--
Posted via http://www.ruby-forum.com/.

--
You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
To post to this group, send email to rubyonrails-talk@googlegroups.com.
To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.

No comments:

Post a Comment