Here’s a SessionController#create
action that supports the classic ‘remember
me’ functionality of login forms.
def create
@user = User.authenticate params[:email], params[:password]
if @user.nil?
flash.now[:notice] = 'Invalid email and/or passowrd'
render :action => :new
else
if remember_me?
@user.remember_me!
cookies[:token] = {
:value => @user.token,
:expires => 1.month.from_now
}
end
session[:user_id] = @user.id
redirect_to home_url
end
end
Now everything does what you expect it to do, I’ve excluded User#authenticate
and SessionController#remember_me?
to keep this short plus they’re obvious.
Let’s look at User#remember_me!
though.
def remember_me!
update_attribute :token, "#{email}-#{Time.now}".to_sha1
end
There I’m using ActiveRecord::Base#update_attribute
to update a token
attribute on a user to a hash of their email and the current time (this is done
to make impersonating sessions less likely).
Now ActiveRecord::Base#update_attribute
is never going to fail because of
failed validation because a user’s validations are not run during it. This
feels bad at first but what error message would you show the user in this
circumstance? Would this update ever fail anyway? I mean if it failed for some
other reason, maybe losing your connection to the database, then I’d want the
exception to bubble up and the user to see the 500 page because that is an
exceptional circumstance and something I don’t expect.
These situations of saving an object without validating it are rare but
sometimes justified. I think Rails agrees because the only method thats
documented to save an object without validating it is
ActiveRecord::Base#update_attribute
and this method only allows you to update
1 attribute at a time. There are other undocumented haxx out there that
allow you to update more than 1 attribute at a time without validation but
they’re undocumented because you shouldn’t be using them. One attribute
without validation is fine but a whole object without validation is
unacceptable.