Reputation: 139
Working through Rails Tutorial 3rd Edition by Michael Hartl: Ch 8 Log in, Log out
I need help understanding why in the session_controller we use a regular 'user' variable while in the users_controller we use an '@user' instance variable.
I noticed that in the session_controller, we use
def create
user = User.find_by...
whereas in the users_controller, we use
def create
@user = User.new...
Michael states, "The main difference between the session form and the signup form is that we have no Session model, and hence no analogue for the @user variable..." referring to this:
form_for(@user)
from the users view versus
form_for(:session, url: login_path)
from the session view.
Is this related? I am still not understanding this. Please let me know if I need to be more clear or specific. Thank you!
Upvotes: 2
Views: 837
Reputation: 7405
I am still not understanding this. Please let me know if I need to be more clear or specific.
Let's try to understand how all these things are working:
In users_controller
, you are instantiating a blank user object by @user = User.new
, which you will be using in your registration form. The reason of doing this is, if you instantiate a new object and pass that object as an argument in form, rails will automatically call create method of users_controller
. Things will be done because of Rails RESTful resource route.
During #create
,
<%= form_for(@user) do |f| %>
...
<% end %>
is equivalent to:
<%= form_for @user, as: :user, url: users_path, html: { class: "new_user", id: "new_user" } do |f| %>
...
<% end %>
On the other hand, if you instantiate an old record like @user = User.find(...)
, rails will call #update
method of users_controller
when you submit the form.
During #update
,
<%= form_for @user do |f| %>
...
<% end %>
is equivalent to:
<%= form_for @user, as: :user, url: user_path(@user), method: :patch, html: { class: "edit_user", id: "edit_user_1" } do |f| %>
...
<% end %>
So, now why instance variable is not used in sessions_controller
#create
action? Okay, if you instantiate an @user
object and use that in login form like what you did in registration form, it will call #create
action of users_controller
instead of #create
action of sessions_controller
.
This is why in login form form_for(:session, url: login_path)
is used. You will receive a Hash
with :session
key in it and since submitting url is explicitly told, that is login_path
, the login information will submitted to #create
action of sessions_controller
.
Hope now things are making sense.
Upvotes: 0
Reputation: 315
Variables user and @user has different scopes
user variable available between words def end
def create
user = User.new
print user
end
create
print user
NameError: undefined local variable ...
you cannot use user variable outside the block of method definition, but if you use variable like @user you can
def create
@user = User.new
print @user
end
create
print @user
#<User:0x007fe1d25596d0>=> nil
So only @user variable can be used in views. Author use local variable user in session_controller, because there no needs to use this variable in view and he use @user on users_controller because if user validation fails it will render form form_for(@user) with values that user entered before submit. So user do not have to fill all form fields again, he need just fix only wrong fields
Upvotes: 0
Reputation: 13067
def create
user = User.find_by...
In this case, user
is a local variable. It is just being used within the same method.
def create
@user = User.new...
Here, @user
is an instance variable, attached to the UsersController
, and by making it an instance variable, it is made accessible in the corresponding views.
So if you look at any views related to users under app/views/users
, there will be a reference to @user
. Nothing of that sort is done in the views related to sessions (i.e. view files under app/views/sessions
folder)
Upvotes: 0