Rails authentication not reacting to wrong username or password - ruby-on-rails

I am building a rails app that requires a log in. I have only one user set up and anytime I enter an incorrect user or password, it does nothing but appends "utf8=✓&authenticity_token=TnSbSndhlfVfO6VLpeGLWgkCdrcXvMFD6gUVyCRax64%3D&email=&password=&commit=Submit" to the URL. I have it set up to say "Invalid username or password" but it's doing nothing. I need it to authenticate and direct the user to the next page. It's not taking me to the next page with the correct username and password either. It just appends that string to the URL and does nothing else. I am new to this so apologies if I'm not being clear enough. Here's my code:
user.rb
class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation
attr_accessor :password
before_save :encrypt_password
validates_confirmation_of :password
validates_presence_of :password, :on => :create
validates_presence_of :email
validates_uniqueness_of :email
def self.authenticate(email, password)
user = find_by_email(email)
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
appplication_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
helper_method :current_user
before_filter :require_login
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def require_login
unless current_user
redirect_to log_in_path, :notice => "Please log in to access this page."
end
end
end
sessions_controller.rb
class SessionsController < ApplicationController
skip_before_filter :require_login
def new
end
def create
user = User.authenticate(params[:email], params[:password])
if user
session[:user_id] = user_id
redirect_to stats_path, :notice => "Welcome"
else
flash.now.alert = "Invalid email or password"
render "new"
end
end
def destroy
session[:user_id] = nil
redirect_to root_url, :notice => "Logged out"
end
end
form view html
<h2 class="form-signin-heading">Log In</h2>
<form class="form-signin">
<%= form_tag sessions_path do %>
<% flash.each do |name, msg| %>
<%= content_tag :div, msg, class: name %>
<% end %>
<%= text_field_tag :email, params[:email], :placeholder => "Email address", :class => "form-control" %><br />
<%= password_field_tag :password, params[:password], :placeholder => "Password", :class => "form-control" %><br />
<%= submit_tag "Submit", :class => "btn btn-lg btn-primary btn-block" %>
<% end %>
</form>

You seem to be missing the ERB in your view to display the flash message. Example:
<% flash.each do |name, msg| -%>
<%= content_tag :div, msg, class: name %>
<% end -%>
See this rails guide for more details...

Related

How do I get my user info to save to the database from the Signup form?

I trying to authentication from scratch in rails 5 and my user information is not being saved when entered into the signup form. I also receive this rails error: ActiveModel::ForbiddenAttributesError
#user = User.new(params[:user])
class User < ApplicationRecord
attr_accessor :password
before_save :encrypt_password
validates_confirmation_of :password
validates_presence_of :password, :on => :create
validates_presence_of :email
validates_uniqueness_of :email
def self.authenticate(email, password)
user = find_by_email(email)
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
<h1>Sign Up</h1>
<%= form_for #user do |f| %>
<% if #user.errors.any? %>
<div class="error_messages">
<h2>Form is invalid</h2>
<ul>
<% for message in #user.errors.full_messages %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :email %><br />
<%= f.text_field :email %>
</p>
<p>
<%= f.label :password %><br />
<%= f.password_field :password %>
</p>
<p>
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %>
</p>
<p class="button"><%= f.submit %></p>
<% end %>
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
redirect_to root_url, :notice => "Signed up!"
else
render "new"
end
end
end
class Post < ApplicationRecord
has_secure_password
end
if you create from scratch make sure for each controller you have strong parameter declaration, let me explain, inside create method you put User.new(user_params), user_params is another method that we put usually on bottom of class, we put the method def user_params, this we declare what allowed field / data that can be passed to our model since you using bcrypt gem, I think the field is same as below
additional info most of rails user using devise gem for authorization user
class UsersController < ApplicationController
def create
#user = User.new(user_params)
# ...
end
private
def user_params
params.require(:user).permit(:username, :email, :password, :salt, :encrypted_password)
end
end

Railscasts: authentication from scratch - missing :session param issue in Rails 4

I'm working through Railscast: authentication from scratch in Rails 4, though the tutorial was built for Rails 3.
For this reason, some changes have had to be made from the original tutorial instructions.
Tutorial: http://railscasts.com/episodes/250-authentication-from-scratch?autoplay=true
Current running into an error
param is missing or the value is empty: session
Thoughts:
I've compared the 2 controllers below. My change from the tutorial is moving the params into a session_params method.
I understand the error is because the hash being posted does not contain a hash like "session" => { }. But I don't have a deep enough understanding of Rails to solve.
Recommended controller (rails 3)
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
My controller (converted to Rails 4)
def create
user = User.authenticate(session_params)
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
private
def session_params
params.require(:session).permit(:email, :password)
end
Up to this point I've only been using Devise for authentication, so a great thanks in advance if you can share any advice.
UPDATE
As requested, form to post session
<h1>Log in</h1>
<%= form_tag sessions_path do %>
<p>
<%= label_tag :email %> <br/>
<%= text_field_tag :email, params[:email] %>
</p>
<p>
<%= label_tag :password %> <br/>
<%= password_field_tag :password %>
</p>
<p class="button"> <%= submit_tag %> </p>
<% end %>
UPDATE 2
Also adding user.rb model
class User < ActiveRecord::Base
attr_accessor :password
before_save :encrypt_password
validates_confirmation_of :password
validates_presence_of :password, :on => :create
validates_presence_of :email
validates_uniqueness_of :email
def self.authenticate(email, password)
user = find_by_email(email)
if user && user.password_hash == BCrypt::Engine.hash_secret(password, password_salt)
user
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
Try this one:
in sessions_controller.rb
def create
#user = User.find_by(email: params[:session][:email].downcase)
if #user && #user.authenticate(params[:session][:password])
session[:user_id] = #user.id
flash[:success] = "#{#user.email}, Successfully Logged In"
redirect_to root_url, :notice => "Logged in!"
else
flash.now[:danger] = "Incorrect User/Password"
render 'new'
end
end
html form
<%= form_for :session, url: :sessions do |f| %>
<div class="field">
<%= f.label :email %>
<%= f.email_field :email %>
</div>
<div class="field">
<%= f.label :password %>
<%= f.password_field :password %>
</div>
<%= f.submit "Sign In", class: "button" %>
<% end %>
routes.rb
post 'sessions' => 'sessions#create'
User.rb
class User < ActiveRecord::Base
has_secure_password
validates_confirmation_of :password
validates_presence_of :password, :on => :create
validates_presence_of :email
validates_uniqueness_of :email
end

Can't log in to my database. Error: "Param is missing or the value is empty: user"

I'm having a trouble with my logging in. It highlights the user_params function as an error in users controller. What could it be?
/views/sessions/new.html.erb or login form
<h1>Log In</h1>
<%= form_tag users_path do %>
<div class="field">
<%= label_tag :email %><br />
<%= text_field :email, params[:email] %>
</div>
<div class="field">
<%= label_tag :password %><br />
<%= password_field_tag :password %>
</div>
<div class="actions"><%= submit_tag "Log In" %></div>
<% end %>
controllers/sessions_controller.rb
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:email])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
redirect_to root_url, notice: "Logged In!"
else
flash.now.alert = "Email or password is invalid"
render "new"
end
end
def destroy
session[:user_id] = nil
redirect_to signup_path, notice: "Logged out!"
end
end
controllers/users_controller.rb
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
session[:user_id] = #user.id
redirect_to user_tasks, notice: "Thank you for signing up!"
else
render "new"
end
end
def index
#users = User.all
end
def show
#user = User.find(params[:id])
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation)
end
end
controllers/application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
def authorize
redirect_to login_url, alert: "Not authorized" if current_user.nil?
end
end
rake routes
Generated parameters
{"utf8"=>"✓", "authenticity_token"=>"jtdA0rITCiFjU9ECiKnDUMh/MHMpqv6u+Bd65PAfpARwYsmb9Dli32wpULfmYa7wpBQiFYxAGHF6flCfJgPOew==", "email"=>"dsadsa", "password"=>[FILTERED]", "commit"=>"Log In"}
Any help?
change this line and try please.
<%= text_field :email, params[:email] %>
to
<%= text_field_tag :email, params[:email] %>
Also majorly add this in your routes file to redirect it to sessions controller create action.
post '/authenticate' => 'sessions#create'
change this tag
<%= form_tag users_path do %>
to
<%= form_tag /authenticate do %>
When you look into the params, they are not coming from the user. Try changing your user_params like below
def user_params
params.permit(:first_name, :last_name, :email, :password, :password_confirmation)
end
I suggest you keep the :user namespace for params in your form
<%= form_tag users_path do |form| %>
<%= fields_for :user do |f| %>
<div class="field">
<%= f.label :email %><br />
<%= f.text_field :email, params[:email] %>
</div>
<div class="field">
<%= f.label :password %><br />
<%= f.password_field :password %>
</div>
<div class="actions"><%= submit_tag "Log In" %></div>
<% end %>
<% end %>
So you can still use params.require(:user) in your controller as usual
Parameters will look like this
{
"utf8"=>"✓",
"authenticity_token"=>"jtdA0rITCiFjU9ECiKnDUMh/MHMpqv6u+Bd65PAfpARwYsmb9Dli32wpULfmYa7wpBQiFYxAGHF6flCfJgPOew==",
"user" => {
"email"=>"dsadsa",
"password"=>[FILTERED],
},
"commit"=>"Log In"
}

If i put wrong password then also form is logged in? how could i solve this issue

sign up page works fine but log in page password not correct then also form is logged in..pls help
This is my users.controller.rb which has new and create action
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
redirect_to '/users/index', :notice => 'Signed In!'
else
render 'new'
end
end
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end
This is my sessions.controller.rb which has new,create and destroy
def new
end
def create
user = User.authenticate(params[:email],[:password])
if user
session[:user_id]= user.id
redirect_to '/users/index', :notice => 'Logged In'
else
flash.now.alert = 'Invalid email or Password'
render 'new'
end
end
def destroy
session[:user_id]= nil
redirect_to root_url, :notice => 'Logged Out'
end
end
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
helper_method :current_user
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
end
This is my new.html.erb for users controller-Sign Up Page
<%= form_for #user do |f| %>
<% if #user.errors.any? %>
<div class = "error_messages">
<h2>Form is Invalid</h2>
<ul>
<% for message in #user.errors.full_messages %>
<li> <%= message %> </li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :email %> <br />
<%= f.text_field :email %>
</p>
<p>
<%= f.label :password %> <br />
<%= f.password_field :password %>
</p>
<p>
<%= f.label :password_confirmation %> <br />
<%= f.password_field :password_confirmation %>
</p>
<p class = button> <%= f.submit %> </p>
<% end %>
This is my new.html.erb for sessions controller(Log In Page)
<%= form_tag sessions_path do %>
<p>
<%= label_tag :email %> <br />
<%= text_field_tag :email, params[:email] %>
</p>
<p>
<%= label_tag :password %> <br />
<%= password_field_tag :password,params[:password] %>
</p>
<p class=> <%= submit_tag %> </p>
<% end %>
This is User Model
class User < ActiveRecord::Base
attr_accessor :password
before_save :encrypt_password
validates_confirmation_of :password
validates_presence_of :password, :on => :create
validates_presence_of :email
validates_uniqueness_of :email
def self.authenticate (email, password)
user = find_by_email(email)
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
You've fallen into the classic "single equals vs double equals trap"
if user && user.password_hash = BCrypt::Engine.hash_secret(password, user.password_salt)
should be
if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
You compared password with single equal sign (=), which is not comparing rather assigning. So the condition returning true always.
Change your authenticate action into this:
def self.authenticate (email, password)
user = find_by_email(email)
hashed_password = BCrypt::Engine.hash_secret(password, user.password_salt)
if user && user.password_hash == hashed_password
user
else
nil
end
end
And you have typo in the following line in your Session Controller's create action:
user = User.authenticate(params[:email], params[:password])

password validation form in rails

I'm new to rails and i want to make a signup login and forget password functionality from scratch so i have been following railscast 250 and 274 episodes..so the problem is, the validations on password and password confirmation fields are working fine on signup form but on the reset password form those validations are not working at all..code is below
model:
class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation, :signup_token
attr_accessor :password
before_save :encrypt_password
before_create {generate_token(:auth_token)}
before_create {generate_token(:signup_token)}
validates :password, length: {minimum: 8}, confirmation: true, presence: true,:on => :create
validates :email, presence: true, uniqueness: true
validates :email, format: {with: /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, message: "not valid"}
def generate_token(column)
begin
self[column] = SecureRandom.urlsafe_base64
end while User.exists?(column => self[column])
end
def self.authenticate(email, password)
user = find_by_email(email)
if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt) && user.active == true
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
def send_password_reset
generate_token(:password_reset_token)
self.password_reset_sent_at = Time.zone.now
save!
UserMailer.password_reset(self).deliver
end
end
password_resets_controller:
class PasswordResetsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:email])
user.send_password_reset if user
redirect_to root_url, :notice => "Email sent with password reset instructions."
end
def edit
#user = User.find_by_password_reset_token!(params[:id])
end
def update
#user = User.find_by_password_reset_token!(params[:id])
if #user.password_reset_sent_at < 2.hours.ago
redirect_to new_password_reset_path, :alert => "Password reset has expired."
elsif #user.update_attributes(params[:user])
redirect_to root_url, :notice => "Password has been reset."
else
render :edit
end
end
end
and views under password reset are
new.html.erb:
<h1>Reset Password</h1>
<%= form_tag password_resets_path, :method => :post do %>
<div class="field">
<%= label_tag :email %>
<%= text_field_tag :email, params[:email] %>
</div>
<div class="actions"><%= submit_tag "Reset Password" %></div>
<% end %>
edit.html.erb:
<h1>Reset Password</h1>
<%= form_for #user, :url => password_reset_path(params[:id]) do |f| %>
<% if #user.errors.any? %>
<div class="error_messages">
<h2>Form is invalid</h2>
<ul>
<% for message in #user.errors.full_messages %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :password %>
<%= f.password_field :password %>
</div>
<div class="field">
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation %>
</div>
<div class="actions"><%= f.submit "Update Password" %></div>
<% end %>

Resources