I have implemented authentication with devise and manage role permissions with CanCan. My application manages Recipes and when I destroy a Recipe, I get my session closed and redirects me to sign_in view...
If I don't check authentication and permissions (see recipes_controller above) it works fine.
It's very strange and I have no idea why this happens. Please help.
Thanks
LOG:
Started POST "/recipes/21" for 127.0.0.1 at Thu Dec 08 19:53:30 +0100 2011
Processing by RecipesController#destroy as HTML
Parameters: {"id"=>"21"}
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = 5 LIMIT 1
Completed 401 Unauthorized in 44ms
Started GET "/users/sign_in" for 127.0.0.1 at Thu Dec 08 19:53:30 +0100 2011
Processing by Devise::SessionsController#new as HTML
Rendered devise/shared/_links.erb (2.5ms)
Rendered devise/sessions/new.html.erb within layouts/application (14.2ms)
Completed 200 OK in 52ms (Views: 20.8ms | ActiveRecord: 0.0ms)
RECIPES_CONTROLLER:
class RecipesController < ApplicationController
before_filter :authenticate_user!
load_and_authorize_resource
def destroy
#recipe = Recipe.find(params[:id])
#recipe.destroy
redirect_to recipes_url, :notice => "Successfully destroyed Recipe."
end
ABILITY:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user
if user.role? :super_admin
can :manage, :all
else if user.role? :super_read_admin
can :read, :all
else
# manage reciped he owns
can :manage, Recipe do |recipe|
recipe.owner == user
end
end
end
end
end
Answer, per asker (see comments below)
You must make sure you include <%= csrf_meta_tags %> in your layout.
============================
(Original reply)
From Completed 401 Unauthorized in 44ms it looks like your user is not allowed to destroy this recipe. Check that recipe.owner.id is 5...
Try this in the console:
user = User.find(5)
puts user.role
ability = Ability.new(user)
ability.can? :destroy, Recipe.find(21)
What is the output of the second and the last commands ?
Related
It shows no errors to aid in locating and fixing the problem. I've checked the database file and it's still empty.
The submit button <div><%= f.submit "Create", class: "btn btn-normal" %></div>
The only thing that changes after submitting is the address. It changes from http://localhost:3000/cars/new to http://localhost:3000/cars
Everything else stays the same. How do i fix this?
Updated the question with the following;
Log
Started GET "/cars/new" for ::1 at 2020-01-26 14:44:53 +0000
(0.1ms) SELECT sqlite_version(*)
Processing by CarsController#new as HTML
User Load (1.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]]
Rendering cars/new.html.erb within layouts/application
Rendered cars/new.html.erb within layouts/application (Duration: 12.1ms | Allocations: 1210)
[Webpacker] Everything's up-to-date. Nothing to do
Rendered shared/_navbar.html.erb (Duration: 0.7ms | Allocations: 103)
Rendered shared/_message.html.erb (Duration: 0.1ms | Allocations: 17)
Completed 200 OK in 496ms (Views: 471.7ms | ActiveRecord: 1.0ms | Allocations: 15750)
Started POST "/cars" for ::1 at 2020-01-26 14:45:06 +0000
Processing by CarsController#create as HTML
Parameters: {"authenticity_token"=>"Oom+xdVDc0PqSwLbLIEP0R8H6U38+v9ISVql4Fr/0WSxZGSrxzTHccsgghd1U30OugcUBAA1R4BtsB0YigAUtA==", "car"=>{"vehicle_type"=>"Sports", "car_type"=>"Private", "seat"=>"5", "colour_type"=>"Black", "transmission_type"=>"Automatic"}, "commit"=>"Create car"}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]]
Rendering cars/new.html.erb within layouts/application
Rendered cars/new.html.erb within layouts/application (Duration: 7.2ms | Allocations: 1144)
[Webpacker] Everything's up-to-date. Nothing to do
Rendered shared/_navbar.html.erb (Duration: 0.2ms | Allocations: 103)
Rendered shared/_message.html.erb (Duration: 0.1ms | Allocations: 17)
Completed 200 OK in 124ms (Views: 114.9ms | ActiveRecord: 0.4ms | Allocations: 14757)
Model app/models/car.rb
class Car < ApplicationRecord
belongs_to :user
validates :vehicle_type, presence: true
validates :car_type, presence: true
validates :seat, presence: true
validates :transmission_type, presence: true
validates :engine, presence: true
end
Controller app/controllers/cars_controller.rb
class CarsController < ApplicationController
before_action :set_car, except: [:index, :new, :create]
before_action :authenticate_user!, except: [:show]
def index
#cars = current_user.cars
end
def new
#car = current_user.cars.build
end
def create
#car = current_user.cars.build(car_params)
if #car.save
redirect_to listing_car_path(#car), notice: "Saved..."
else
render :new, notice: "Something went wrong..."
end
end
def show
end
def listing
end
def pricing
end
def description
end
def photo_upload
end
def features
end
def location
end
def update
if #car.update(car_params)
flash[:notice] = "Saved..."
else
flash[:notice] = "Something went wrong..."
end
redirect_back(fallback_location: request.referer)
end
private
def set_car
#car = Car.find(params[:id])
end
def car_params
params.require(:car).permit(:vehicle_type, :car_type, :seat, :transmission_type, :engine, :fuel_type, :colour_type, :window_type, :listing_name, :summary, :is_tv, :is_air, :is_internet, :is_sunroof, :is_bluetooth, :is_dvd, :is_gps, :is_usb, :is_audio, :is_airbags, :price, :active)
end
end
TLDR:
Solution is that you should either provide engine and user_id in params or you should remove presence true validation and add optional true case (for user association) from model.
Explanation:
If your model says that it should validate presence of engine then how can you not provide engine param (in form). When you post the form without engine, what happens is that your model does not save it and as you have handled that case, it moves on. As it belongs to user, same goes for user ID. although you could make it optional too by adding optional: true both in schema and model (because a car can "be" without a user IRL but depends here in your use-case).
Going one step further, to exactly understand the issue yourself, use pry or byebug to see the params and happenings in runtime. Easier and faster way to verify the error is that put a bang in front of create method and it will show the error like: if #car.save!. One more thing: copy the car params and try to do this in rails console yourself manually with bang. It will give you the cause. These things will help you diagnose model save/create issues in rails.
Happy Coding :)
From your log file
Started POST "/cars" for ::1 at 2020-01-26 14:45:06 +0000
Shows that the create action is being called on the cars controller
The parameters being passed in are
{"authenticity_token"=>"Oom+xdVDc0PqSwLbLIEP0R8H6U38+v9ISVql4Fr/0WSxZGSrxzTHccsgghd1U30OugcUBAA1R4BtsB0YigAUtA==", "car"=>{"vehicle_type"=>"Sports", "car_type"=>"Private", "seat"=>"5", "colour_type"=>"Black", "transmission_type"=>"Automatic"}, "commit"=>"Create car"}
The first method called on your create action is authenticate_user
before_action :authenticate_user!, except: [:show]
You can see that this happens
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]]
According to your log the next thing that happens is
Rendering cars/new.html.erb within layouts/application
Which means that the else clause was hit render :new, notice: "Something went wrong..."
#car = current_user.cars.build(car_params)
if #car.save
redirect_to listing_car_path(#car), notice: "Saved..."
else
render :new, notice: "Something went wrong..."
end
Therefore the car did not save so validation must have failed.
Your new car form should have an errors loop to display all the errors. If it did have this then your user (You) would know what went wrong
Something like this
<% if car.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(car.errors.count, "error") %> prohibited this car from being saved:</h2>
<ul>
<% car.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
Should do the trick but it's standard in all rails generated forms so it should be there anyway
Devise's sign_in_after_reset_password setting supposedly signs in my user after successfully resetting the password.
However, what it seems to do in practice is to redirect back to '/', which ultimately results in showing the login page.
Why isn't it signing me in?
In user.rb:
devise :database_authenticatable,
:recoverable,
:validatable,
:encryptable
In application_controller.rb:
class ApplicationController < ActionController::Base
protect_from_forgery
before_action :authenticate_user!, unless: :devise_controller?
#omitting business logic filters and helpers
end
Custom routes (solely to change the paths. Have tried to keep the resulting route list identical to the defaults other than the names):
devise_for :users, skip: [ :passwords, :sessions ]
devise_scope :user do
get 'users/login' => 'devise/sessions#new', as: 'new_user_session'
post 'users/login' => 'devise/sessions#create', as: 'user_session'
delete 'users/logout' => 'devise/sessions#destroy', as: 'destroy_user_session'
post 'users/password' => 'devise/passwords#create', as: 'user_password'
get 'users/password/forgot' => 'devise/passwords#new', as: 'new_user_password'
get 'users/password/reset' => 'devise/passwords#edit', as: 'edit_user_password'
patch 'users/password' => 'devise/passwords#update', as: nil
put 'users/password' => 'devise/passwords#update', as: nil
end
The investigation so far:
I had a lot of minor deviations from the structure of a sample devise application which I have been golfing back bit by bit to try and make things easier to figure out. So now my authenticate_user! filter is being specified in the same place as most examples.
Something I noticed is that after successfully resetting the password, it isn't clearing the reset password token. Maybe that's normal, it's just suspicious.
I have debugged in Devise's PasswordsController itself and after it executes the sign_in line, signed_in? does return true.
I have attempted to breakpoint inside signed_in? at the point of requesting the root path, but it seems like I get the 401 error from the web server without signed_in? ever being called. So perhaps Warden is directly kicking me out before the application even gets to run.
I'm starting to run out of avenues for investigation, so I thought I would post it here in case anyone had seen the exact same issue before.
Logs of the event:
Started PUT "/users/password" for ::1 at 2016-07-13 17:14:44 +1000
Processing by Devise::PasswordsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"[FILTERED]", "user"=>{"reset_password_token"=>"[FILTERED]", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Change my password"}
Can't verify CSRF token authenticity
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."reset_password_token" = ? ORDER BY "users"."id" ASC LIMIT 1 [["reset_password_token", "[FILTERED]"]]
(0.0ms) begin transaction
Note Load (0.1ms) SELECT "notes".* FROM "notes" WHERE "notes"."notable_id" = ? AND "notes"."notable_type" = ? [["notable_id", 2], ["notable_type", "User"]]
Organisation Load (0.1ms) SELECT "organisations".* FROM "organisations" WHERE "organisations"."id" = ? LIMIT 1 [["id", 1]]
User Exists (0.1ms) SELECT 1 AS one FROM "users" WHERE ("users"."login" = 'test1' AND "users"."id" != 2) LIMIT 1
(0.0ms) commit transaction
Redirected to http://localhost:3000/
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1 [["id", 2]]
Completed 302 Found in 44ms (ActiveRecord: 1.7ms)
Started GET "/" for ::1 at 2016-07-13 17:14:44 +1000
Processing by SessionsController#welcome as HTML
Completed 401 Unauthorized in 0ms (ActiveRecord: 0.0ms)
Started GET "/users/login" for ::1 at 2016-07-13 17:14:44 +1000
Processing by Devise::SessionsController#new as HTML
Rendered users/shared/_links.html.erb (0.1ms)
Rendered users/sessions/new.html.erb within layouts/application (2.2ms)
Completed 200 OK in 148ms (Views: 147.3ms | ActiveRecord: 0.0ms)
Not really answering the question itself, but I found a workaround which is at least a solution, even if it's a bad solution.
In my ApplicationController:
after_action :fix_login_after_password_reset, if: ->(controller) {
controller.controller_path == 'devise/passwords' &&
controller.action_name == 'update'
}
def fix_login_after_password_reset
user = current_user
if user && user.errors.empty?
user = User.where(id: user.id).first
sign_out
bypass_sign_in(user)
end
end
Essentially, I found a post where people who wrote their own "change password" pages found that Devise (or Warden?) was logging out the user immediately afterwards. The workaround for them was to change the call to sign_in to bypass_sign_in.
In this situation, though, Devise have already called sign_in. So I thought I'd try adding a filter that applies onto to their one action with the problem, and sign the user out, then sign in a fresh copy of the user. This fixes the issue - now the user is signed in and the root page appears.
I don't like this solution much though so I'm still digging inside Warden to try and figure out why the user is not being signed in with a call to sign_in.
I had the same issue, and found that passing an extra parameter to the sign_up function solves the problem:
sign_in(#user, :bypass => true)
This was something I found in this tutorial for setting up omniauth with a finish_signup feature. My implementation below is part of a feature I'm writing for a user to change their password and still retain their status as a logged in user.
~/app/controllers/users_controller.rb
class UsersController < ApplicationController
before_action :set_current_user, only: [:edit_password, :update_password]
def edit_password
end
def update_password
if #user.update(user_params)
# Sign in the user by passing validation in case their password changed
sign_in(#user, :bypass => true)
redirect_to root_path
else
render :edit_password
end
end
private
def set_current_user
#user = User.find(current_user.id)
end
end
~/app/views/users/edit_password.html.erb
<%= form_for(#user, :url => { :action => "update_password" } ) do |f| %>
<div class="field">
<%= f.label :password, "Password" %><br />
<%= f.password_field :password, :autocomplete => "off" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %>
</div>
<div class="action_container">
<%= f.submit %>
</div>
<% end %>
routes.rb
resource :user, only: [:none] do
collection do
get :edit_password
patch :update_password
end
end
We are using Devise, Rails_Admin and Simple_Token_Authentication (for API) in our application.
Everything is working fine except for sign out. When we click on Sign out, following request is made and the user gets signed out.
Started DELETE "/admins/sign_out" for 127.0.0.1 at 2015-07-12 18:50:44
+0530 Processing by Devise::SessionsController#destroy as HTML Parameters:
{"authenticity_token"=>"rtSRPzpRN7cWEk8wV8q6VDAUB575ZV46JeFFlMFVOQc="}
Admin Load (0.4ms) SELECT "admins".* FROM "admins" WHERE
"admins"."id" = 1 ORDER BY "admins"."id" ASC LIMIT 1 (0.1ms)
begin transaction (0.1ms) commit transaction Completed 204 No
Content in 700ms (ActiveRecord: 0.5ms)
The problem is that the page does not redirect after sign out.
On pressing the sign out button again, here is the request:
Started DELETE "/admins/sign_out" for 127.0.0.1 at 2015-07-12 19:01:59
+0530 Processing by Devise::SessionsController#destroy as HTML Parameters:
{"authenticity_token"=>"dHuxA5hRosyquhlsRmchK3vW9bQOCM/YXYXUNMxTufc="}
Filter chain halted as :verify_signed_out_user rendered or redirected
Completed 204 No Content in 1ms (ActiveRecord: 0.0ms)
Here is the application controller (app/controllers/application_controller.rb):
class ApplicationController < ActionController::Base
protect_from_forgery
skip_before_filter :verify_signed_out_user
respond_to :html, :json
protected
# Overwriting the sign_out redirect path method
def after_sign_out_path_for(resource_or_scope)
request.referrer
end
end
Here is the devise related code in app/config/initializers/rails_admin.rb
config.authenticate_with do
warden.authenticate! scope: :admin
end
config.current_user_method(&:current_admin)
Please suggest. Thanks in advance!
The problem is in your after_sign_out_path_for(resource_or_scope).
request.referrer redirects to the current page.
Change the after_sign_out_path_for(resource_or_scope) accordingly. If you want to redirect to root_path, then below would work.
def after_sign_out_path_for(resource_or_scope)
root_path
end
I first discovered an issue where it didn't appear as if the user is getting logged in with this logic:
_header.html.erb:
<% if user_signed_in? %>
<li><%= link_to "Log out", destroy_user_session_path, method: :delete %></li>
<% else %>
<li><%= link_to "Sign in", new_user_session_path %></li>
<% end %>
Then I tried adding this to application_controller.rb:
before_filter :authenticate_user!
And I kept getting looped back to the login page (even with valid credentials).
It appears as if my user sessions aren't working — although I can see on my RailsAdmin console that the sign in count and last sign in date are showing as if they are logging in.
Here's my user.rb:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :omniauthable, :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable
belongs_to :company
has_and_belongs_to_many :productlines
end
And my routes.rb:
Rails.application.routes.draw do
mount RailsAdmin::Engine => '/admin', as: 'rails_admin'
devise_for :users, :controllers => { :omniauth_callbacks => "omniauth_callbacks" }
root 'productlines#index'
end
And omniauth_callbacks_controller.rb:
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def google_oauth2
#user = User.from_omniauth(request.env["omniauth.auth"])
if #user.persisted?
flash.notice = "Signed in through Google"
sign_in_and_redirect #user
return
else
session["devise.user_attributes"] = #user.attributes
flash.notice = "You are almost Done! Please provide a password to finish setting up your account"
redirect_to new_user_registration_path
end
end
end
Update: Here is my application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
skip_before_filter :verify_authenticity_token, :if => Proc.new { |c| c.request.format == 'application/json' }
before_filter :productline
def productline
#productlines = Productline.all
end
end
Every time I sign in, I'm rerouted back to the root_path and the "Sign In" link still appears.
Edit: Here is the log output when I click Sign In:
Started POST "/users/sign_in" for ::1 at 2015-07-06 23:20:15 -0400
Processing by Devise::SessionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"6Eh4Qw3qErGmsppatErFZYhTOZHs8DhCOMXqGAMrBzRdTd72L5rIGAChLDvnI/GzOv1kQsyL43o/B6AQQtnk4Q==", "user"=>{"email"=>"broy#bullhorn.com", "password"=>"[FILTERED]", "remember_me"=>"0"}, "commit"=>"Log in"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."email" = ? ORDER BY "users"."id" ASC LIMIT 1 [["email", "b#gmail.com"]]
(0.1ms) begin transaction
SQL (0.3ms) UPDATE "users" SET "last_sign_in_at" = ?, "current_sign_in_at" = ?, "sign_in_count" = ?, "updated_at" = ? WHERE "users"."id" = ? [["last_sign_in_at", "2015-07-07 03:17:08.826634"], ["current_sign_in_at", "2015-07-07 03:20:15.963289"], ["sign_in_count", 93], ["updated_at", "2015-07-07 03:20:15.964239"], ["id", 4]]
(1.5ms) commit transaction
Redirected to http://localhost:3000/
Completed 302 Found in 73ms (ActiveRecord: 2.1ms)
Started GET "/" for ::1 at 2015-07-06 23:20:15 -0400
Processing by ProductlinesController#index as HTML
Productline Load (0.1ms) SELECT "productlines".* FROM "productlines"
Rendered productlines/index.html.erb within layouts/application (2.1ms)
Rendered layouts/_header.html.erb (1.7ms)
Completed 200 OK in 48ms (Views: 47.3ms | ActiveRecord: 0.1ms)
Started GET "/" for ::1 at 2015-07-06 23:20:16 -0400
Processing by ProductlinesController#index as HTML
Productline Load (0.2ms) SELECT "productlines".* FROM "productlines"
Rendered productlines/index.html.erb within layouts/application (104.8ms)
Rendered layouts/_header.html.erb (1.1ms)
Completed 200 OK in 155ms (Views: 154.1ms | ActiveRecord: 0.2ms)
Do you want to put an exception in first on your authenticate user? That way it is not trying to run an authentication before current_user/#user/etc has even been set. For example if your root is index:
before_action :authenticate_user!, :except => [:index]
Then - be sure to have the better_errors gem and throw in some nonsense jibberish in your if user_signed_in? statement, refresh the page to trigger the console in the browser. See if #user or current_user or what you are using got set at all in the first place. I would then debug backwards from there.
https://github.com/charliesome/better_errors
Finally here is a stackoverflow link I came upon with a similar issue and a few answers below:
Rails devise: user_signed_in? not working
I am trying to create a simple authentication system but I seem to have a problem.
The signup process works fine, but when I try to login with the exact same information, I can't (I get "Invalid email or password"). As I saw, the hash comparison returns false. Here is my code:
#sessions_controller.rb
def create
user = User.authenticate(params[:email], params[:password])
if user
session[:user_id] = user.id
redirect_to root_url, :notice => "Logged in!"
else
flash.now.alert = "Invalid email or password"
render "new"
end
end
and
class User < ActiveRecord::Base
attr_accessor :password
before_save :encrypt_password
validates_confirmation_of :password
validates_presence_of :password, :on => :create
validates_presence_of :name
validates_presence_of :email
validates_uniqueness_of :email
def self.authenticate(email, password)
user = User.where(email: email).first
# throw Exception.new(user.password_hash) #uncaught throw #<Exception: $2a$10$9FHhPyb7BW01ktwTTgZHX.hlKKv4ajX/dX9D/xNGmZoajJTdGG4N.>
# throw Exception.new(user.password_salt) #uncaught throw #<Exception: $2a$10$9FHhPyb7BW01ktwTTgZHX.>
# throw Exception.new(BCrypt::Engine.hash_secret(password, user.password_salt)) #uncaught throw #<Exception: $2a$10$9FHhPyb7BW01ktwTTgZHX.O62xalJit020Jb0g5XDdB5V8dGMslQS>
if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
user
else
nil
end
end
def encrypt_password
if password.present?
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
end
end
end
So, as you can see in the commented lines in user.rb, the password hash that I get when trying to log in is not the same with the original one. Obviously, the password I enter is the correct one.
user.password_hash = $2a$10$9FHhPyb7BW01ktwTTgZHX.hlKKv4ajX/dX9D/xNGmZoajJTdGG4N.
user.password_salt = $2a$10$9FHhPyb7BW01ktwTTgZHX.
BCrypt::Engine.hash_secret(password, user.password_salt) = $2a$10$9FHhPyb7BW01ktwTTgZHX.O62xalJit020Jb0g5XDdB5V8dGMslQS
Can you please give me a hint here? What is that I do wrong?
Thanks a lot!
//later edit: also adding the users controller, perhaps this can help.
class UsersController < ApplicationController
def new
#user = User.new(user_params)
end
def create
#user = User.new(user_params)
if #user.save
redirect_to root_url, :notice => "Signed up!"
else
render "new"
end
end
private
def user_params
params.fetch(:user).permit(:name, :email, :password, :password_confirmation) if params[:user]
end
end
Edit: posting the logs for signing up/logging in
Started GET "/sign_up" for 127.0.0.1 at 2013-10-11 11:23:13 +0300
Processing by UsersController#new as HTML
Rendered users/new.html.erb within layouts/application (31.8ms)
Completed 200 OK in 48ms (Views: 41.8ms | ActiveRecord: 1.2ms)
Started POST "/users" for 127.0.0.1 at 2013-10-11 11:24:30 +0300
Processing by UsersController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"LPLEs9at6BLGgjikYynnEzA/JAMMVl9IYGId1zEyNEg=", "user"=>{"name"=>"johntest", "email"=>"johntest#johntest.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Create User"}
(0.1ms) BEGIN
User Exists (0.4ms) SELECT 1 AS one FROM `users` WHERE `users`.`email` = BINARY 'johntest#johntest.com' LIMIT 1
SQL (0.3ms) INSERT INTO `users` (`created_at`, `email`, `name`, `password_hash`, `password_salt`, `updated_at`) VALUES ('2013-10-11 08:24:30', 'johntest#johntest.com', 'johntest', '$2a$10$tpDFvkFUC.OPckDm6xacU.xkjFmECg2CDpsi3cjTJNX6K58ujHOn6', '$2a$10$tpDFvkFUC.OPckDm6xacU.', '2013-10-11 08:24:30')
(39.2ms) COMMIT
Redirected to http://localhost:3000/
Completed 302 Found in 141ms (ActiveRecord: 40.0ms)
Started GET "/" for 127.0.0.1 at 2013-10-11 11:24:30 +0300
Processing by TroublesController#frontpage as HTML
Trouble Load (0.2ms) SELECT `troubles`.* FROM `troubles`
CACHE (0.0ms) SELECT `troubles`.* FROM `troubles`
Rendered troubles/_marker_infowindow.html.erb (0.8ms)
Rendered troubles/_marker_infowindow.html.erb (0.1ms)
Rendered /home/alex/.rvm/gems/ruby-2.0.0-p247/gems/gmaps4rails-1.5.6/app/views/gmaps4rails/_gmaps4rails.html.erb (1.9ms)
Rendered troubles/frontpage.html.erb within layouts/application (3.9ms)
Completed 200 OK in 21ms (Views: 13.5ms | ActiveRecord: 0.2ms)
[...](loading assets)
Started GET "/log_in" for 127.0.0.1 at 2013-10-11 11:24:52 +0300
Processing by SessionsController#new as HTML
Rendered sessions/new.html.erb within layouts/application (1.1ms)
Completed 200 OK in 14ms (Views: 12.8ms | ActiveRecord: 0.0ms)
Started POST "/sessions" for 127.0.0.1 at 2013-10-11 11:25:05 +0300
Processing by SessionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"LPLEs9at6BLGgjikYynnEzA/JAMMVl9IYGId1zEyNEg=", "name"=>"johntest", "email"=>"johntest#johntest.com", "password"=>"[FILTERED]", "commit"=>"Log in"}
User Load (0.4ms) SELECT `users`.* FROM `users` WHERE `users`.`email` = 'johntest#johntest.com' ORDER BY `users`.`id` ASC LIMIT 1
Rendered sessions/new.html.erb within layouts/application (1.7ms)
Completed 200 OK in 99ms (Views: 10.9ms | ActiveRecord: 0.4ms)
[...](loading assets)
So I went to the sign up page, filled in the details, I was forwarded to the homepage and it said "Signed up!". I clicked login, entered the details and it says "Invalid email or password".
Bcrypt is decrypting the right way but the culprit in your code is the before_save :encrypt_password just change the before save event as before_create event. with before_save , Every time you update the user record encrypt_password is called and it is encrypting the password field that way you are losing the first encrypted password which never matches though you give the correct password. I got stuck up with the same issue, after a deep analysis I got to know the fix.