I'm working my way through Michael Hartl's Rails Tutorial and I am currently on chapter 8, in section 8.55. I am trying to trouble shoot a failure that I'm receiving via that test, which I can't figure out where to solve.
FAIL["test_current_user_returns_right_user_when_session_is_nil", SessionsHelperTest, 0.05582] test_current_user_returns_right_user_when_session_is_nil#SessionsHelperTest (0.06s)
--- expected
+++ actual
## -1 +1 ##
-#<User id: 584273342, name: "Kyle Example", email: "kyle#example.com", created_at: "2014-12-27 20:09:35", updated_at: "2014-12-27 20:09:35", password_digest: "$2a$04$yK7dSRppfGCqCbrXXZ34meDB2jEulxy9BDVNH32qLDz...", remember_digest: "$2a$04$GT65nJ.fE90LasXpaT1HruCChf.hl.4fvMrtx2iV48V...">
+nil
test/helpers/sessions_helper_test.rb:11:in `block in <class:SessionsHelperTest>'
My test code is using the following code.
require 'test_helper'
class SessionsHelperTest < ActionView::TestCase
def setup
#user = users(:kyle)
remember(#user)
end
test "current_user returns right user when session is nil" do
assert_equal #user, current_user
assert is_logged_in?
end
test "current_user returns nil when remember digest is wrong" do
#user.update_attribute(:remember_digest, User.digest(User.new_token))
assert_nil current_user
end
end
SessionsHelper module
module SessionsHelper
# Logs in the given user.
def log_in(user)
session[:user_id] = user.id
end
#Remembers a user in a persistent session.
def remember(user)
user.remember
cookies.permanent.signed[:user_id] = user.id
cookies.permanent[:remember_token] = user.remember_token
end
#Returns the user corresponding to the remember token cookie.
def current_user
if (user_id = session[:user_id])
#current_user ||= User.find_by(id: user_id)
elsif (user_id = cookies.signed[:user_id])
user = User.find_by(id: user_id)
if user && user.authenticated?(cookies[:remember_token])
log_in user
#current_user = user
end
end
end
#Returns the current logged-in user (if any).
def current_user
#current_user ||= User.find_by(id: session[:user_id])
end
#Returns true if the user is logged in, false otherwise.
def logged_in?
!current_user.nil?
end
def log_out
session.delete(:user_id)
#current_user = nil
end
# Forgets a persistent session.
def forget(user)
user.forget
cookies.delete(:user_id)
cookies.delete(:remember_token)
end
# Logs out the current user.
def log_out
forget(current_user)
session.delete(:user_id)
#current_user = nil
end
end
User model
class User < ActiveRecord::Base
attr_accessor :remember_token
before_save { email.downcase! }
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
has_secure_password
validates :password, length: { minimum: 6 }
# Returns the hash digest of the given string.
def User.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
#Returns a random token.
def User.new_token
SecureRandom.urlsafe_base64
end
#Remembers a user in the database for use in persistent sessions
def remember
self.remember_token = User.new_token
update_attribute(:remember_digest, User.digest(remember_token))
end
#Returns true if the given token matches the digest.
def authenticated?(remember_token)
return false if remember_digest.nil?
BCrypt::Password.new(remember.digest).is_password?(remember_token)
end
# Forgets a user.
def forget
update_attribute(:remember_digest, nil)
end
end
Any ideas on what could have caused this?
You have two
def current_user
methods in module SessionsHelper
remove this one(which is old one and doesn't check for cookies presence):
#Returns the current logged-in user (if any).
def current_user
#current_user ||= User.find_by(id: session[:user_id])
end
it is being used in your test currently, because it is defined below updated one.
Related
I have been reading about Good Manners of Rails, and there are many articles like this one:
http://codefol.io/posts/Where-Do-I-Put-My-Code/
and seems like helpers should only be used for views. I don't understand well why, but if that would be the case and this is my sessions_helper.rb file:
module SessionsHelper
def log_in(user)
session[:user_id] = user.id
end
def logged_in?
!current_user.nil?
end
def log_off
forget(current_user)
session.delete(:user_id)
#current_user = nil
end
def current_user
if (user_id = session[:user_id])
#current_user ||= User.find_by(id: user_id)
elsif (user_id = cookies.signed[:user_id])
user = User.find_by(id: user_id)
if user&.authenticated?(cookies[:remember_token])
log_in user
#current_user = user
end
end
end
def remember(user)
user.remember
cookies.permanent.signed[:user_id] = user.id
cookies.permanent[:remember_token] = user.remember_digest
end
def forget(user)
user.forget
cookies.delete(:user_id)
cookies.delete(:remember_token)
end
end
and this is my model user.rb
class User < ApplicationRecord
has_many :post
attr_accessor :remember_token, :activation_token
before_save { self.email = email.downcase }
before_create :create_activation_digest
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i.freeze
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
has_secure_password
validates :password, presence: true, length: { minimum: 6 }
# Returns the hash digest of the given string.
def self.digest(string)
Digest::SHA1.hexdigest(string.to_s)
end
# Returns a random token.
def self.new_token
SecureRandom.urlsafe_base64
end
# Remembers a user in the database for use in persistent sessions.
def remember
self.remember_token = User.new_token
update_attribute(:remember_digest, User.digest(remember_token))
end
# Returns true if the given token matches the digest.
def authenticated?(remember_token)
return false if remember_digest.nil?
BCrypt::Password.new(remember_digest).is_password?(remember_token)
end
# Forgets a user.
def forget
update_attribute(:remember_digest, nil)
end
# Creates and assigns the activation token and digest.
def create_activation_digest
self.activation_token = User.new_token
self.activation_digest = User.digest(activation_token)
end
end
what should I do to refactor it in a good way to be correct?
sorry If I am requesting too much help, but it is just that I am learning Rails and I don't understand this part very well.
That article is really just states the authors opinion. AbstractController::Helpers actually has helper method thats used to specifically include helpers into the controller so its hardly an officially endorsed opinion.
It can be debated endlessly exactly where exactly this peice of code belongs but since you're going to be using it in both the view and controller I would say just put it in app/helpers and be done with it. It makes a lot more sense than placing it somewhere else and then manually including it in the view context.
However this code should probally be split into two modules as only part of it makes sense to use from the view.
module SessionsHelper
def logged_in?
!current_user.nil?
end
def current_user
if (user_id = session[:user_id])
#current_user ||= User.find_by(id: user_id)
elsif (user_id = cookies.signed[:user_id])
user = User.find_by(id: user_id)
if user&.authenticated?(cookies[:remember_token])
log_in user
#current_user = user
end
end
end
end
# app/controllers/concerns/authenticable.rb
module Authenticable
def log_in(user)
session[:user_id] = user.id
end
def log_off
forget(current_user)
session.delete(:user_id)
#current_user = nil
end
def remember(user)
user.remember
cookies.permanent.signed[:user_id] = user.id
cookies.permanent[:remember_token] = user.remember_digest
end
def forget(user)
user.forget
cookies.delete(:user_id)
cookies.delete(:remember_token)
end
end
To satisfy my supervisor (or code reviewer), I had to copy/paste all session helper code on every single controller file, since copying it in application_controller was not enough.
The specific code below from the book using Rails 4
I believed in rails 5 required strong parameters that may cause error in Rails 5.
Please anyone could share me. How to apply permit and require for the following code)
From model user.rb
def remember
remember_token = User.new_token
update_attribute(:remember_digest, User.digest(remember_token))
end
error (in rails 5)
NoMethodError in SessionsController#create
undefined method `update_attribute' for #<Class
Here what I did.
def remember
remember_token = User.new_token
update_attribute(:remember_digest, User.digest(params:[remember_token]))
end
error:
NoMethodError in SessionsController#create
undefined method `update_attribute' for #<Class:0x007fd23b30a790> Did you mean? _default_attributes
Tobe clear: those method called from sessionshelper.erb
module SessionsHelper
# Logs in the given user.
def log_in(user)
session[:user_id] = user.id
end
# Remembers a user in a persistent session.
def remember(user)
User.remember
cookies.permanent.signed[:user_id] = user.id
cookies.permanent[:remember_token] = user.remember_token
end
# Returns the user corresponding to the remember token cookie.
def current_user
if (user_id = session[:user_id])
#current_user ||= User.find_by(id: user_id)
elsif (user_id = cookies.signed[:user_id])
user = User.find_by(id: user_id)
if user && user.authenticated?(cookies[:remember_token])
log_in user
#current_user = user
end
end
end
# Returns true if the user is logged in, false otherwise.
def logged_in?
!current_user.nil?
end
# Forgets a persistent session.
def forget(user)
user.forget
cookies.delete(:user_id)
cookies.delete(:remember_token)
end
# Logs out the current user.
def log_out
forget(current_user)
session.delete(:user_id)
#current_user = nil
end
end
user.rb
class User < ApplicationRecord
attr_accessor :remember_token, :activation_token, :reset_token, :remember_digest
before_save { self.email = email.downcase }
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
has_secure_password
validates :password, presence: true, length: { minimum: 6 }
class << self
# Returns the hash digest of the given string.
def digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
def remember
remember_token = User.new_token
update_attribute(:remember_digest, User.digest(remember_token))
end
# Returns a random token.
def new_token
SecureRandom.urlsafe_base64
end
end
# Returns true if the given token matches the digest.
def authenticated?(remember_token)
BCrypt::Password.new(remember_digest).is_password?(remember_token)
end
# Forgets a user.
def forget
update_attribute(:remember_digest, nil)
end
def activate
update_attribute(:activated, true)
update_attribute(:activated_at, Time.zone.now)
end
end
sessionscontroller.rb
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
log_in user
remember user
redirect_to user
else
flash.now[:danger] = 'Invalid email/password combination'
render 'new'
end
end
def destroy
log_out
redirect_to url_for(:controller => :sessions, :action => :new)
end
end
The issue is in the helper, the line
You are calling the remember method with the User class, so it is showing undefined method for class. Instead call with user object
User.remember
should be,
user.remember
def remember(user)
user.remember
cookies.permanent.signed[:user_id] = user.id
cookies.permanent[:remember_token] = user.remember_token
end
You should be calling update_attribute on the user
try
current_user.update_attribute(a: b)
in your SessionsController#create
update_attributes is an instance method not a class method, so first thing you need to call it on an instance of User class.
like:
#user.update_attributes(:remember_digest, User.digest(params:[remember_token]))
Try this once.
i have a similar implementation,maybe this might help you
in user.rb
def create_confimation_token
generate_token(:confirmation_token)
update_attribute(:expiration,Time.zone.now + 2.days)
save!
end
def generate_token(column)
begin
self[column] = SecureRandom.urlsafe_base64
end
end
u should call update_attributes for a user object.
helper.rb
def remember(user)
user.remember
cookies.permanent.signed[:user_id] = user.id
cookies.permanent[:remember_token] = user.remember_token
end
model.rb
def remember
remember_token = new_token
self.update_attributes(:remember_digest, digest(remember_token))
end
It worked Now
What happened are the
class << self in user.rb
cause following method not working.
def remember
remember_token = User.new_token
update_attribute(:remember_digest, User.digest(remember_token))
end
User.remember in SessionsHelper should be
user.remember
Thanks everyone
one my my tests receiving the following error in Chapter 8 of Hartl's Rails Tutorial.
> 1) Error:
> UsersLoginTest#test_login_with_valid_information_followed_by_logout:
> NoMethodError: undefined method `forget' for #<Class:0x000000079be3b0>
> app/helpers/sessions_helper.rb:30:in `forget'
> app/helpers/sessions_helper.rb:37:in `log_out'
> app/controllers/sessions_controller.rb:18:in `destroy'
> test/integration/users_login_test.rb:40:in `block in <class:UsersLoginTest>'
I have tried copying and pasting code exactly as it is in the tutorial, but it doesn't seem to be solving the issue.
Here is my Sessions Helper
module SessionsHelper
def log_in(user)
session[:user_id] = user.id
end
def remember(user)
user.remember
cookies.permanent.signed[:user_id] = user.id
cookies.permanent[:remember_token] = user.remember_token
end
def current_user
if (user_id = session[:user_id])
#current_user ||= User.find_by(id: user_id)
elsif (user_id = cookies.signed[:user_id])
user = User.find_by(id: user_id)
if user && user.authenticated?(cookies[:remember_token])
log_in user
#current_user = user
end
end
end
def logged_in?
!current_user.nil?
end
def forget(user)
user.forget
cookies.delete(:user_id)
cookies.delete(:remember_token)
end
# Logs out the current user.
def log_out
forget(current_user)
session.delete(:user_id)
#current_user = nil
end
end
And my sessions controller is below
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
log_in user
remember user
redirect_to user
else
flash.now[:danger] = 'Invalid email/password combination'
render 'new'
end
end
def destroy
log_out if logged_in?
redirect_to root_url
end
end
Any suggestions would be very much appreciated!
Here we can see the importance of really looking closely at the error message. It says there is a "No Method Error". OK. So we're doing something with the Users and there's no method. A user is a modeled thing, so let's look at app/models/user.rb:
class User < ActiveRecord::Base
attr_accessor :remember_token
before_save { self.email = email.downcase }
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
has_secure_password
validates :password, presence: true, length: { minimum: 6 }
# Returns the hash digest of the given string.
def User.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
# Returns a random token.
def User.new_token
SecureRandom.urlsafe_base64
end
# Remembers a user in the database for use in persistent sessions.
def remember
self.remember_token = User.new_token
update_attribute(:remember_digest, User.digest(remember_token))
end
# Returns true if the given token matches the digest.
def authenticated?(remember_token)
BCrypt::Password.new(remember_digest).is_password?(remember_token)
end
# Forgets a user.
def forget
update_attribute(:remember_digest, nil)
end
end
we see that at the very end, there is a method being created called "forget"
def forget
#something
end
That opens up the method to calls from other controllers and helpers, which you've already created in the Sessions section.
This test failure is killing me. I'm following along with the railstutorial.org e-book. I've researched this failure as much as I can. I've read up on testing over and over, but I'm just missing something, and I have been stuck on this issue for nearly a week. I'm at wits end. Thank you for any insight.
rake test results in:
1) Failure:
SessionsHelperTest#test_current_user_returns_right_user_when_session_is_nil [/Users/test_user/app/test/helpers/sessions_helper_test.rb:11]:
--- expected
+++ actual
## -1 +1 ##
-#<User id: 762146111, first_name: "Michael", middle_name: "James", last_name: "Example", suffix: "Jr", created_at: "2015-08-01 14:13:26", updated_at: "2015-08-01 14:13:27", email: "michael#example.com", password_digest: "$2a$04$.AOr7J8q/Ft7Gu3HTNWjDet5kU2O8uFwV9l...", remember_digest: "$2a$04$./yszAudU5o/tovax413r.poDLg5N33a0XD...">
+nil
user.rb
class User < ActiveRecord::Base
attr_accessor :remember_token
before_save { self.email = email.downcase }
validates :first_name, presence: true, length: { maximum: 20 }
validates :last_name, presence: true, length: { maximum: 30 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 }, format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
validates :password, presence: true, length: { minimum: 6 }
has_secure_password
# Returns the hash digest of the given string.
def User.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
# returns a url-safe random string of 20 characters, each character having 64 possibilities
def User.new_token
SecureRandom.urlsafe_base64
end
def remember
self.remember_token = User.new_token
update_attribute(:remember_digest, User.digest(:remember_token))
end
# Returns true if the given token matches the digest.
def authenticated?(remember_token)
return false if remember_digest.nil?
BCrypt::Password.new(remember_digest).is_password?(remember_token)
end
def forget
update_attribute(:remember_digest, nil)
end
end
sessions_controller.rb
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
log_in user
params[:session][:remember_me] == '1' ? remember(user) : forget(user)
redirect_to user
else
flash.now[:danger] = 'Invalid email/password combination'
render 'new'
end
end
def destroy
log_out if logged_in?
redirect_to root_url
end
end
sessions_helper.rb
module SessionsHelper
# Logs in the given user.
def log_in(user)
session[:user_id] = user.id
end
def remember(user)
user.remember
cookies.permanent.signed[:user_id] = user.id
cookies.permanent[:remember_token] = user.remember_token
end
def forget(user)
user.forget
cookies.delete(:user_id)
cookies.delete(:remember_token)
end
# Returns the current logged-in user (if any).
def current_user
if (user_id = session[:user_id])
#current_user ||= User.find_by(id: user_id)
elsif (user_id = cookies.signed[:user_id])
user = User.find_by(id: user_id)
if user && user.authenticated?(cookies[:remember_token])
log_in user
#current_user = user
end
end
end
# Returns true if the user is logged in, false otherwise.
def logged_in?
!current_user.nil?
end
def log_out
forget(current_user)
session.delete(:user_id)
#current_user = nil
end
end
sessions_helper_test.rb
require 'test_helper'
class SessionsHelperTest < ActionView::TestCase
def setup
#user = users(:michael)
remember(#user)
end
test "current_user returns right user when session is nil" do
assert_equal #user, current_user
assert is_logged_in?
end
test "current_user returns nil when remember digest is wrong" do
#user.update_attribute(:remember_digest, User.digest(User.new_token))
assert_nil current_user
end
end
users.yml
michael:
first_name: Michael
middle_name: James
last_name: Example
suffix: Jr
email: michael#example.com
password_digest: <%= User.digest('password') %>
The failing test makes no sense to me : the user is never logged in, and still the test expects current_user to returns a user.
Try with the 2 following tests :
test "current_user returns right user when session is set" do
log_in #user
assert_equal #user, current_user
assert is_logged_in?
end
test "current_user returns no user when session is nil" do
assert_nil current_user
assert !is_logged_in?
end
Firstly, learn RSpec instead of test/unit.
Secondly, what's your version of Rails?
Generally the code you are presenting is honestly a really shitty implementation of login/logout functions. You don't need to store these functions in helper (controller can't access helper functions, at least not without magic, and you most definitely will need current_user function in your controllers), you don't need some rememberance 'tokens', and you don't need to mix 'cookies' and 'session' variables (by default 'session' IS special cookie, already signed/checked by Rails itself).
So just rewrite that example:
class User < ActiveRecord::Base
# validations, etc., what you have in your initial example
# just forget about 'remember token' and such stuff
end
class ApplicationController
# we don't want these methods to become actions
private
def log_in(user)
session[:user_id] = user.id
end
def current_user
#current_user ||= (session[:user_id] && User.find(session[:user_id]))
end
def logged_in?
current_user.present?
end
def log_out
# it's good idea to clear EVERYTHING from session on log-out, not just user_id
reset_session
#current_user = nil
end
end
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
log_in user
redirect_to user
else
flash.now[:danger] = 'Invalid email/password combination'
render 'new'
end
end
def destroy
log_out
redirect_to root_url
end
end
Yeah, that looks much better. Unless you see a really really good reason to make your code look like mess with all that 'token' stuff.
Now to the specs!
Install rspec-rails (basically, add couple of lines to your Gemfile)
rails g rspec:controller sessions in your terminal
Something like that in your newly generated spec:
-
describe SesssionsController
# move your fixtures to appropriate folder beforehand (basically, from test/something to spec/something)
fixtures :users
before do
#michael = users(:michael)
end
it 'logs user in'
post :create, session: {email: 'michael#example.com', password: 'password'}
expect(controller.send(:current_user)).to_not be_nil
expect(controller.send(:current_user).id).to eq #michael.id
end
end
Didn't test that code, I must admit, so if you encounter some errors which are not obvious, feel free to ask for further help in comments to my reply.
The problem is in the remember method in the User model.
def remember
self.remember_token = User.new_token
update_attribute(:remember_digest, User.digest(:remember_token))
end
should be
def remember
self.remember_token = User.new_token
update_attribute(:remember_digest, User.digest(remember_token))
end
I'm not sure on the specifics of why the original doesn't work, but putting the remember_token there as a symbol is what's breaking it.
In reference to the current best answer:
Adding a call to log_in in the test only circumvents the problem above, and actually makes the test pointless. What you're trying to test here, in this test:
test 'current_user returns right user when session is nil' do
assert_equal #user, current_user
assert is_logged_in?
end
is that the part of the current_user method that handles users that have a signed cookie, but don't have an active session, is working (logging the user in, and assigning them to #current_user).
def current_user
if (user_id = session[:user_id])
#current_user ||= User.find_by(id: user_id)
elsif (user_id = cookies.signed[:user_id])
user = User.find_by(id: user_id)
#### THIS BIT ####
if user && user.authenticated?(cookies[:remember_token])
log_in user
#current_user = user
end
##################
end
end
So by just logging in the user in the setup, you are passing the current_user method a user with an active session, which means it's not ever reaching the part of the method you're trying to test.
I am working through Hartl's Ruby on Rails Tutorial (3rd Ed.) and just completed Chapter 8. One of the goals of the chapter is to have the application sign users out by deleting the session’s user id and remove the permanent cookie from the browser. However, I've logged out of the app and then typed http://localhost:3000/users/1 in the browser and have been taken back to the profile for user 1. Is this a security issue?
The log in screen:
Logged in:
Logged out and directed back to the home page:
Now, here is where I'm confused. If I type in users/1 in the browser's address bar, I seem to be taken back to user #1's page, although the upper right corner doesn't show me as logged in.
Does anybody think that this is a security issue?
Here is some of the code related to the app. Am I missing something?
users_controller.rb
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
log_in #user
flash[:success] = "Welcome to the Sample App!"
redirect_to #user
else
render 'new'
end
end
def edit
#user = User.find(params[:id])
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
end
sessions_controller.rb
class SessionsController < ApplicationController
def new
end
def create
#user = User.find_by(email: params[:session][:email].downcase)
if #user && #user.authenticate(params[:session][:password])
log_in #user
params[:session][:remember_me] == '1' ? remember(#user) : forget(#user)
redirect_to #user
else
flash.now[:danger] = 'Invalid email/password combination'
render 'new'
end
end
def destroy
log_out if logged_in?
redirect_to root_url
end
end
sessions_helper.rb
module SessionsHelper
# Logs in the given user.
def log_in(user)
session[:user_id] = user.id
end
# Remembers a user in a persistent session.
def remember(user)
user.remember
cookies.permanent.signed[:user_id] = user.id
cookies.permanent[:remember_token] = user.remember_token
end
# Returns the user corresponding to the remember token cookie.
def current_user
if (user_id = session[:user_id])
#current_user ||= User.find_by(id: user_id)
elsif (user_id = cookies.signed[:user_id])
user = User.find_by(id: user_id)
if user && user.authenticated?(cookies[:remember_token])
log_in user
#current_user = user
end
end
end
# Returns true if the user is logged in, false otherwise.
def logged_in?
!current_user.nil?
end
# Forgets a persistent session.
def forget(user)
user.forget
cookies.delete(:user_id)
cookies.delete(:remember_token)
end
# Logs out the current user.
def log_out
forget(current_user)
session.delete(:user_id)
#current_user = nil
end
end
user.rb
class User < ActiveRecord::Base
attr_accessor :remember_token
before_save { self.email = email.downcase }
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
has_secure_password
validates :password, length: { minimum: 6 }
# Returns the hash digest of the given string.
class << self
def digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
# Returns a random token.
def new_token
SecureRandom.urlsafe_base64
end
end
# Remembers a user in the database for use in persistent sessions.
def remember
self.remember_token = User.new_token
update_attribute(:remember_digest, User.digest(remember_token))
end
# Returns true if the given token matches the digest.
def authenticated?(remember_token)
return false if remember_digest.nil?
BCrypt::Password.new(remember_digest).is_password?(remember_token)
end
# Forgets a user.
def forget
update_attribute(:remember_digest, nil)
end
end
Thanks.
No. At this point there's no security issue. You're issuing a GET request for /users/1 and Rails delivers that. There is nothing preventing that page from being shown.
As sevenseacat explained in a comment above, there are no access restrictions there.