Ruby Rails User's Email Being overwritten - ruby-on-rails

Playing around with authentication from scratch and for some reason my users email address is not being saved to the DB. When I fire up the console and pull a random user, their email is always nil, but have validations set for the presence of email and am get a successful user created message. This was working before and not sure what broke it. I know this is something super simple but it has got me for the last few hours and am hoping a second pair of eyes can tell me what I'm doing wrong. GitHub link below
[https://github.com/smarandache1990/auth][1]
<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 %>
<% #user.errors.full_messages_for(:email).each do |message| %>
<div><%= message %></div>
<% end %>
</p>
<p>
<%= f.label :password %><br />
<%= f.password_field :password %>
<% #user.errors.full_messages_for(:password).each do |message| %>
<div><%= message %></div>
<% end %>
</p>
<p>
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %>
<% #user.errors.full_messages_for(:password_confirmation).each do |message| %>
<div><%= message %></div>
<% end %>
</p>
<p class="button"><%= f.submit %></p>
<% end %>
<h1>Sign 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 "Log in" %></p>
<% end %>
class User < ApplicationRecord
attr_accessor :email, :password, :password_confirmation
before_save :encrypt_password
validates :password, confirmation: true, on: :create
validates :password_confirmation, presence: true
#validates_presence_of :password, :on => :create
#validates_confirmation_of :password
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
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
redirect_to log_in_path, :notice => "Signed up!"
else
render :new, status: :unprocessable_entity
end
end
private
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end
class SessionsController < ApplicationController
def new
end
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[:notice] = "Wrong username or password"
render :new, status: :unprocessable_entity
end
end
def destroy
session[:user_id] = nil
redirect_to root_url, :notice => "Logged out!"
end
end

Remove the email from the attr_acessor (here).
attr_accessor creates the getters and setters for all attributes listed there. So, basically, you're overriding these methods for the email attribute.
About the validation, use this:
validates :email, presence: true, uniqueness: true

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

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])

Ruby on Rails login form, always returns error can't be blank

I'm trying to setup a user sign-up system, and when I input an email and password, After pressing submit I always get the same errors: password can't be black, email can't be blank. I am a ruby newbie and have a hard time wrapping my head around parameters setting. If anyone can spot what I did wrong and point it out please do so. I would also be grateful for any documentation and explanations on what I did wrong.
I'm using rails 4.2.1 and ruby 2.2.1p85
Thanks
my controller:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(params[:user_params])
if #user.save
redirect_to root_url, :notice => "Signed up!"
else
render "new"
end
end
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end
my new.html.erb:
<h1>Sign Up</h1>
<%= form_for #user do |f| %>
<%if #user.errors.any? %>
<div class="error_messages">
<h2>From 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 %>
my model(user.rb)
class User < ActiveRecord::Base
attr_accessor :password
before_save :encrypt_password
validates_confirmation_of :password
validates_presence_of :password
validates_presence_of :email
validates_uniqueness_of :email
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 need to use user_params correctly. params[:user_params] will return nil.
Your create action should looks like:
def create
#user = User.new(user_params)
...
...
end
params[:user_params] is nil, use #user = User.new(user_params) instead

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 %>

Getting error on validation error when signin / signup are on home page

In my first Rails app I had a page for user signin (sessions new) and a page for user signup (users new), but in my second Rails app I want the signin and signup on the home page.
I finally got this working when the user enters correct info, for example a user email that actually exists and correct password.
But if the user enters wrong info, like an registered user email that does not exist, or wrong password, I get an error:
undefined method 'model_name' for NilClass:Class
Anyone have any ideas? Relevant code (only) below.
------------- routes.rb ----------------
MyApp::Application.routes.draw do
resources :sessions, only: [:create, :destroy]
resources :users
root to: 'static_pages#home'
end
-------------- user.rb ----------------
class User < ActiveRecord::Base
attr_accessible :email, :email_confirmation, :firstname, :lastname, :password, :password_confirmation,
validates :email, presence: true
validates :firstname, presence: true
validates :lastname, presence: true
validates :password, length: { within: 6..16 }, if: :password
validates :password_confirmation, presence: true, if: :password
end
-------- users_controller.rb --------------
class UsersController < ApplicationController
def new
if signed_in?
redirect_to root_path
else
#user = User.new
end
end
def create
if signed_in?
redirect_to root_path
else
#user = User.new(params[:user])
if #user.save
sign_in #user
flash[:success] = "Welcome #{#user.firstname} to MyApp. Thanks for signing up!"
redirect_to root_path
else
render 'new'
end
end
end
end
------------- sessions_controller.rb ----------------
class SessionsController < ApplicationController
def create
user = User.find_by_email(params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
sign_in user
redirect_back_or user_path(current_user)
else
flash.now[:error] = "Invalid email/password combination"
user = User.create(email: params[:session][:email], password: params[:session][:password])
render 'static_pages/home', locals: { showerror: true, user: user }
end
end
end
------- static_pages_controller.rb --------------
class StaticPagesController < ApplicationController
def home
#user = User.new
end
end
----------- application_helper.rb -------------
module ApplicationHelper
def field_class(resource, field_name)
if resource.errors[field_name].length > 0
return " custom_error1 ".html_safe
else
return "".html_safe
end
end
def error_notifier(error)
if error
return " custom_error1 ".html_safe
else
return "".html_safe
end
end
end
------------ views/static_pages/home.html.erb ----------------
<div>
<div>
<!-- signin form -->
<%= render 'static_pages/new_session' %>
<!-- signup form -->
<%= render 'static_pages/new_user' %>
</div>
</div>
------------- views/static_pages/_new_session.html.erb ---------------
<div>
<h3>Sign in</h3>
<%= form_tag(sessions_path) do %>
<div>
<div>
<%= label :session, :email %>
<%= text_field :session, :email, class: (error_notifier(#showerror) + 'info_inline_control info_textfield') %>
</div>
<div>
<%= label :session, :password %>
<%= password_field :session, :password, class: (error_notifier(#showerror) + 'info_inline_control info_textfield') %>
</div>
</div>
<div class="signin_link">
<%= submit_tag "Sign in" %>
<p class="reminders">Forgot your password?
<%= link_to "Reset password", new_password_reset_path %></p>
</div>
<% end %>
</div>
------------- views/static_pages/_new_user.html.erb ---------------
<div>
<h3>Sign up</h3>
<%= form_for(#user) do |f| %>
<%= render 'user_fields', f: f %>
<div>
<%= f.submit "Create Account" %>
</div>
<% end %>
</div>
------------- views/static_pages/_user_fields.html.erb ---------------
<%= render 'shared/error_messages', object: f.object %>
<div>
<div>
<%= f.label :firstname %>
<%= f.text_field :firstname, class: (field_class(#user, :firstname) + 'info_inline_control info_textfield') %>
</div>
<div>
<%= f.label :lastname %>
<%= f.text_field :lastname, class: (field_class(#user, :lastname) + 'info_inline_control info_textfield') %>
</div>
<div>
<%= f.label :email %>
<%= f.text_field :email, class: (field_class(#user, :email) + 'info_inline_control info_textfield') %>
</div>
<div>
<%= f.label :password %>
<%= f.password_field :password, class: (field_class(#user, :password) + 'info_inline_control info_textfield') %>
</div>
<div>
<%= f.label :password_confirmation, "Confirm Password" %>
<%= f.password_field :password_confirmation, class: (field_class(#user, :password_confirmation) + 'info_inline_control info_textfield') %>
</div>
</div>
Thanks in advance!
class SessionsController < ApplicationController
def create
#user = User.find_by_email(params[:session][:email].downcase)
if #user && #user.authenticate(params[:session][:password])
sign_in #user
redirect_back_or user_path(current_user)
else
flash.now[:error] = "Invalid email/password combination"
#user = User.create(email: params[:session][:email], password: params[:session][:password])
#showerror = true
render 'static_pages/home'
end
end
end
you should use instance variable #user,because in view #user is used when register failed.

Resources