Require old password to make new password - ruby-on-rails

Right now every time I change anything in user/edit the form requires the user to set a new password. I would like for it to require the current password (how can I ask for current password?) only incase a new password is entered. How can I achieve this, thanks a lot for this.
<%= form_for(#user, :html => {:multipart => true}) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.text_field :name, placeholder: :name %>
<%= f.text_field :email, placeholder: :email %>
<%= f.password_field :password, placeholder: "Enter new password" %>
<%= f.password_field :password_confirmation, placeholder: "Confirm new password" %>
<%= f.submit "Save changes", class: "btn btn-large btn-primary" %>
<% end %>

Using some info from rails_has_elegance and the web I came up with the following solution.
user/edit view:
<%= form_for(#user, :html => {:multipart => true}) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.text_field :name, placeholder: :name %>
<%= f.text_field :email, placeholder: :email %>
<%= password_field_tag :current_password, params[:current_password], placeholder: "Current password" %>
<%= f.password_field :password, placeholder: "New password (optional)" %>
<%= f.password_field :password_confirmation, placeholder: "Confirm new password" %>
<% end %>
User model:
validates :password, :on => :create
validates :password_confirmation, presence: true, :on => :update, :unless => lambda{ |user| user.password.blank? }
User controller:
def update
#user = User.find(params[:id])
user = User.find_by_email(current_user.email).try(:authenticate, params[:current_password])
if user && #user.update_attributes(params[:user])
flash[:success] = "Profile updated"
sign_in #user
redirect_to #user
else
flash.now[:error] = "Incorrect Current Password" unless user
sign_in #user
render 'edit'
end
end

You can add in your form old_password field
<%= f.password_field :old_password, placeholder: "Enter current password" %>
Add it to attr_accessible :old_password and attr_accessor :old_password
And then you can validate it
validate :correct_old_pass, :on => :update
def correct_old_pass
errors[:old_password] << 'Incorrect pass' if your_check_method
end

You can create a separate form for changing password. And you can ask for current password just like you ask for a new one:
<%= form_for(#user, :html => {:multipart => true}) do |f| %>
<%= f.password_field :password, placeholder: "Enter current password" %>
<%= f.password_field :password, placeholder: "Enter new password" %>
<%= f.password_field :password_confirmation, placeholder: "Confirm new password" %>
<%= f.submit "Save changes", class: "btn btn-large btn-primary" %>
<% end %>

I would suggest making extra edit_password and update_password actions for that in your users_controller:
#user = User.find(params[:id])
user = User.find_by_email(current_user.email).try(:authenticate, params[:current_password])
if user && #user.update_attributes(params[:user])
flash[:success] = "Password updated!"
(sign_in #user)
redirect_to ...
In your form just use these fields:
<%= label_tag :current_password, "Current password:" %>
<%= password_field_tag :current_password, params[:current_password] %>
<%= form.label :password, "New password:" %>
<%= form.password_field :password %>
<%= form.label :password_confirmation, "Confirm new password" %>
<%= form.password_field :password_confirmation %>

Related

Rendering file in create action is not working in rails in windows 10

In my users views new.html.erb
<% provide(:title, 'SignUp') %>
<%= form_with(model: #user, local: true) do |f| %>
<%= f.label :name, "Name" %>
<%= f.text_field :name %>
<br>
<%= f.label :email, "Email" %>
<%= f.email_field :email %>
<br>
<%= f.label :password, "Password" %>
<%= f.password_field :password %>
<br>
<%= f.label :password_confirmation, "Confirm Password" %>
<%= f.password_field :password_confirmation %>
<br>
<%= f.submit "Create Account", class: "btn btn-outline-success" %>
<% end %>
In my user controller users_controller.rb looks like:-
class UsersController < ApplicationController
def new
#user = User.new
end
def show
#user = User.find(params[:id])
end
def create
#user = User.new(user_params)
if #user.invalid?
puts "Hi"
flash[:success] = "Invalid Data"
render 'new'
else
flash[:success] = "Welcome to sample app"
#user.save
redirect_to #user
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
end
This is my errors file /views/shared/_errors.html.erb
<% if #user.errors.any? %>
<div class="alert alert-danger">
The form contains <%= pluralize(#user.errors.count, "error") %>
</div>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li> <%= msg %> </li>
<% end %>
</ul>
<% end %>
render 'new' is not working in create action. I include the errors.html.erb file in new file so it can display the error, but it is not working.
Try form_for instead of form_with.
<%= form_for(#user) do |f| %>
<%= f.label :name, "Name" %>
<%= f.text_field :name %>
<br>
<%= f.label :email, "Email" %>
<%= f.email_field :email %>
<br>
<%= f.label :password, "Password" %>
<%= f.password_field :password %>
<br>
<%= f.label :password_confirmation, "Confirm Password" %>
<%= f.password_field :password_confirmation %>
<br>
<%= f.submit "Create Account", class: "btn btn-outline-success" %>
<% end %>

Form data not getting saved to database

I'm new to RoR and I'm trying to create a sign-up form. When I click on 'Create my account', data does not get saved to the database. I have added resources: users to my routes file. Is there something else I'm missing?
This is my view (signup.html.erb)
Sign Up
<%= form_for #user, :url => { :action => "create" } do |f| %>
<%= f.label :emp_id,"Employee ID" %><br>
<%= f.text_field :emp_id, class: 'form-control' %><br><br>
<%= f.label :password, "Password" %><br>
<%= f.password_field :password, class: 'form-control' %><br><br>
<%= f.label :password_confirmation, "Password Confirmation" %><br>
<%= f.password_field :password_confirmation, class: 'form-control' %><br><br>
<%= f.submit "Create my account", class: "btn btn-primary" %>
<% end %>
This is my controller
class UsersController < ApplicationController
def new
#user = User.new
end
def signup
#user = User.new
end
def show
#user = User.find(params[:id])
end
def create
#user = User.new(user_params)
if #user.save
render 'login'
else
render 'signup'
end
end
def user_params
params.require(:user).permit(:emp_id, :password)
end
end
You need to permit :password_confirmation
def user_params
params.require(:user).permit(:emp_id, :password, :password_confirmation)
end
And make sure there are no other validations like email presence or that will cause validations to fail

Rails submit form with get parameters from url

I have form for signup user and when this url have get parameter like
http://localhost:3000/signup?list_id=10
need transfer this parameters to action for create user
<%= form_for(#user) do |f| %>
<%= render 'shared/error_messages', user: #user %>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
<%= f.submit yield(:button_text), class: "btn btn-primary" %>
in this action user create dont see this parameter
def create
debugger
#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
(byebug) params<ActionController::Parameters {"utf8"=>"✓", "authenticity_token"=>"I5+lc0T2fqy2Ie56rMnkR6Eff60nJmiuaTob7xAqknB6YgHZpmEByyRpCanpnNqyO9H/wMWbm7IumdXRyUABcA==", "user"=>{"name"=>"Ivan", "email"=>"ss#ss.com", "password"=>"222", "password_confirmation"=>"222"}, "commit"=>"Create my account", "controller"=>"users", "action"=>"create"} permitted: false>
It's available in your params hash so you can add it to your form as a hidden field so it will be submitted with the other params. Then make sure to whitelist that parameter in your controller.
First, add the virtual attribute to your User model if :list_id isn't already a persisted attribute for Users. This is done by adding the following line in your user.rb model file:
attr_accessor :list_id
Then add the following inside your form view:
<%= f.hidden_field :list_id, :value => params[:list_id] %>
Then in your controller where you whitelist your params you would add :list_id as a secure parameter. You didn't post your strong_params method but should be like:
def user_params
params.require(:user).permit(:list_id, :name, :email, :password, :password_confirmation)
end

Updating User Password using Devise for Omniauth in Rails 4

I'm new to Devise and I'm trying to update user password for the users who signed up through normal sign up(form) and via Omniauth(facebook,google_oauth2).
Below is my code.
Edit form:
#app/views/devise/registrations/edit.html.erb
<h2>Change Your Details</h2>
<div><b><i>View or update your Current Email and Password <%= link_to 'Click Here', '#', :id => 'email_change' %></b></i></div>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
<%= devise_error_messages! %>
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
<div style="color:red">Currently waiting confirmation for: <%= resource.unconfirmed_email %>. Please confirm the new email address before using it for sign in.</div>
<% end %>
<div id='display_email'><%= f.label :current_email %> <i>(this email is currently used for email alerts and sign in)</i><br />
<%= f.email_field :email, autocomplete: "off", :class => 'form-control' %> <i>(edit this field to change your email)</i></div>
<% if resource.provider.blank? %>
<div><%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password, autocomplete: "off", :class => 'form-control' %></div>
<% end %>
<div><%= f.label :new_password %> <i></i><br />
<%= f.password_field :password, autocomplete: "off", :class => 'form-control' %></div>
<div><%= f.label :new_password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off", :class => 'form-control' %></div>
<br>
<div><%= f.submit "Update", :class => 'btn btn-lg btn-primary btn-block' %></div>
<% end %>
Update method:
#app/controllers/registrations_controller.rb
def update
# For Rails 4
account_update_params = devise_parameter_sanitizer.sanitize(:account_update)
# delete field if it is blank, so it does not update
permitted_update_fields_hash = [:first_name, :last_name, :email, :primary_phone, :password, :password_confirmation]
permitted_update_fields = [:first_name, :last_name, :email, :primary_phone, :password, :password_confirmation]
puf = permitted_update_fields.length - 1
index = 0
while index <= puf
if account_update_params[permitted_update_fields_hash[index]].blank?
account_update_params.delete(permitted_update_fields[index])
end
index += 1
end
# required for settings form to submit when password is left blank
if account_update_params[:password].blank?
account_update_params.delete("password")
account_update_params.delete("password_confirmation")
end
#user = User.find(current_user.id)
if #user.update_attributes(account_update_params)
set_flash_message :notice, :updated
# Sign in the user bypassing validation in case their password changed
sign_in #user, :bypass => true
if #user.role == "renter"
redirect_to renter_dashboard_path(resource.renter.slug)
else
redirect_to request.referer
end
else
redirect_to request.referer
end
end
Problem:
Users who signed up through facebook,google_oauth2 can't able to provide current password because they actually don't know the current password. This is because Devise generates a random password on sign up
user.password = Devise.friendly_token[0,20]
Current Solution:
Currently I'm hiding the current_password field for the users who signed up through facebook & google_oauth2(see the below image)
Question:
Is there any better alternative approach for this situation?

Custom Profile Edit Page. Devise Gem

I'm new to Rails.
I have a register page in my app. Also a profile page. I'm trying to make an edit page where I can edit users email, password and all. I want to do all this using devise..
I have reached so far. here is my edit page.
<div class="edit_profile_page">
<%= form_for(current_user, :url => '/update', :html => { :method => :put }) do |f| %>
<div><%= f.label :email %><br />
<%= f.email_field :email, :autofocus => true %></div>
<div><%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
<%= f.password_field :password, :autocomplete => "off" %></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %></div>
<div><%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password %></div>
<div><%= f.submit "Update" %></div>
<% end %>
</div>
I'm stuck here. What url should i pass.. Also if this url points to a method say
def update_profile
end
what should i write inside that method so that the password will get updated like the one happened while registration.
Or
There is an edit page inside Device. How should i write my routes to reach there.
You can also create own ProfilesController, example below:
Routes:
#routes.rb
resource :profile
Controller:
# coding: utf-8
class ProfilesController < ApplicationController
before_filter :authenticate_user!
def show
#user=current_user
#user.email = nil unless #user.email.scan('#example.com').empty?
render 'devise/profile/edit'
end
def update
#user=current_user
if #user.update_attributes(params[:user])
sign_in 'user', #user, :bypass => true
flash[:notice] = t('users.profile.edit.updated')
respond_to do |format|
format.html { redirect_to '/'}
end
else
render 'devise/profile/edit'
end
end
end
Views
#views/devise/profile/edit.html.haml
%h3
= t('users.profile.basic_settings')
= simple_form_for #user, :url => profile_path, :html => { :method => :put } do |f|
-#= f.error_messages
= f.input :name, :placeholder=>t('activerecord.placeholders.name')
= f.input :email, :placeholder=>t('activerecord.placeholders.email')
= f.submit t('users.profile.change_name'), :class => "btn btn-primary"
= t('users.profile.change_password')
= simple_form_for #user, :url => profile_path, :html => { :method => :put } do |f|
-#= f.error_messages
= f.input :password , :error_html => { :id => "password_error"}
= f.input :password_confirmation
= f.submit t('users.profile.change_password'), :class => "btn btn-primary"

Resources