Couldn't find User with id=update_password with Devise - ruby-on-rails

I'm using devise on a Rails application and for various reasons I needed to add a custom password change, using solution 3 from here: https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-edit-their-password
I've looked through various other questions and tried augmenting my routes in a number of ways but the url always comes up /users/update_password (without a parameter passed), or /users/update_password.254 (with a parameter passed). I need it to be /users/254/update_password.
Here is the Users Controller I'm working with (relevant methods are update_password and user_params).
class UsersController < ApplicationController
inherit_resources
load_and_authorize_resource
before_filter :authenticate_user!
def destroy
name = #user.to_s
destroy!(notice: "User #{#user.to_s} was deleted.")
end
def edit
#user = current_user
end
def update_password
#user = User.find(current_user.id)
if #user.update_with_password(user_params)
sign_in #user, :bypass => true
redirect_to root_path
else
render "edit"
end
end
private
def build_resource_params
[params.fetch(:user, {}).permit(:name, :email, :phone_number, :password, :password_confirmation).tap do |p|
p[:institution_pid] = build_institution_pid if params[:user][:institution_pid]
p[:role_ids] = build_role_ids if params[:user][:role_ids]
end]
end
def build_institution_pid
institution = Institution.find(params[:user][:institution_pid])
authorize!(:add_user, institution)
institution.id
end
def build_role_ids
[].tap do |role_ids|
roles = Role.find(params[:user][:role_ids].reject &:blank?)
roles.each do |role|
authorize!(:add_user, role)
role_ids << role.id
end
end
end
def user_params
params.required(:user).permit(:password, :password_confirmation, :current_password)
end
end
This is the relevant portion of routes.rb
devise_for :users
resources :users do
collection do
get 'password'
put 'update_password'
end
end
This is the view I created to go with it:
<div class="page-header">
<h1>Change Password</h1>
</div>
<%= 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="field">
<%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password %>
</div>
<div class="action_container">
<%= f.submit %>
</div>
And this is the link: (currently with a parameter but I've tried without as well)
<li><%= link_to "Change Password", update_password_users_path(current_user) %></li>
When I click that link I get routed to a page that says ActiveRecord::RecordNotFound in UsersController#show, Couldn't find User with id=update_password.
I tried to follow the instructions pretty closely and I've tried to fiddle with the routes a couple times to get it to work and I'm pretty lost at this point. Has anyone seen this before and can help? Thanks!

To achieve what you need, you will have the following routes:
resources :users do
patch 'update_password', on: :collection
get 'edit_password', on: :member
end
Then you'll add a link that would lead user to update password form. The link should look like as follows:
<li><%= link_to "Change Password", edit_password_user_path(current_user) %></li>
The link would lead to users/edit_password.html.erb:
<div class="page-header">
<h1>Change Password</h1>
</div>
<%= 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="field">
<%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password %>
</div>
<div class="action_container">
<%= f.submit %>
</div>
<% end %>
When form is submitted, that would trigger update_password in UsersController. Here is the code for controller:
class UsersController < ApplicationController
def edit_password
#user = current_user
end
def update_password
#user = User.find(current_user.id)
if #user.update_with_password(user_params)
sign_in #user, :bypass => true
redirect_to root_url
else
render "edit_password"
end
end
private
def user_params
params.required(:user).permit(:password, :password_confirmation, :current_password)
end
end

Related

How i can do this when user click on buyer role it will go to homepage and when user select seller role it will go to Dashboard

This is application Controller for devise
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
private
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:role])
end
end
signup form from devise and adding role
<h2>Sign up</h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
</div>
<div class="field">
<%= f.label :password %>
<% if #minimum_password_length %>
<em>(<%= #minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "new-password" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "new-password" %>
</div>
This is a role code
There is a problem when user select buyer on signup page it should go the homepage , when user select seller it should go to the selled dashboard
<%= f.label :role %>
<%= f.select :role, User.roles.keys %>
Here is the submit button
<div class="actions">
<%= f.submit "Sign up", data: {turbo: false} %>
</div>
<% end %>
<%= render "devise/shared/links" %>
You didn't provide much context about what you do in your controller when a user is signed up and how you build the form. Therefore I will just assume that it is a very basic form and all attributes are nested properly in the request and that the create action follows a simple scaffolding structure.
Then you basically only need to change where to redirect the user to depending on its role after the record was created.
# in controllers/users.rb
def create
user = User.new(user_params)
if user.save
case user.role
when 'user'
redirect_to root_path
when 'seller'
redirect_to dashboard_path
end
else
render :edit
end
end

Update information of different user with extension of Devise

I setup a platform that uses Devise to create and manage users and CanCanCan to manage permissions. Users have a role (admin or client) that allows them access to certain areas. Admin users have the ability to can :manage, :all
I extended Devise so that I have a users/registrations and users/sessions controller.
Admin users have access to views in a ManagerController dashboard that allows them to manage other users. I've figured out how to show the details of a different user, but I can't figure out how to save the information. I get errors that indicate it either can't find the User or that it requires a POST route.
I'm fairly new to Rails, so it could be something simple. I was able to find solutions that included the regular Devise installation, but not the extension. I feel like the problem may be in my routes.
I also can't create new users from here either.
Routes.rb
get 'users' => 'manager#users'
get 'users/edit' => 'manager#edit'
post 'users/edit' => 'manager#edit'
get 'users/new' => 'manager#new'
devise_for :users, :controllers => { registrations: 'users/registrations', sessions: 'users/sessions' }
devise_scope :user do
authenticated :user do
root 'users/registrations#edit', as: :authenticated_root
end
unauthenticated do
root 'users/sessions#new', as: :unauthenticated_root
end
end
Manager Controller
class ManagerController < ApplicationController
authorize_resource :class => false
include ManagerHelper
def users
#users = User.where.not(:id => current_user.id)
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
flash[:notice] = "Successfully created User."
redirect_to root_path
else
render :action => 'new'
end
end
def edit
#user = User.find(params[:id])
#companies = Company.all
end
def update
#user = User.find(params[:id])
params[:user][:id].delete(:password) if params[:user][:password].blank?
params[:user][:id].delete(:password_confirmation) if params[:user][:password].blank? and params[:user][:password_confirmation].blank?
if #user.update(user_params)
flash[:notice] = "Successfully updated User."
redirect_to root_path
else
render :action => 'edit'
end
end
end
private
def user_params
params.require(:user).permit(:email, :first_name, :last_name, :company_id, :role, :password, :password_confirmation)
end
end
ManagerHelper
module ManagerHelper
def resource_name
:user
end
def resource
#resource ||= User.new
end
def devise_mapping
#devise_mapping ||= Devise.mappings[:user]
end
end
Manager/Edit.html.erb
<h2>Edit <%= resource_name.to_s.humanize %></h2>
<%= form_for(resource, :as => #user, :url => edit_user_registration_path(resource_name)) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<%= f.hidden_field :id %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
</div>
<div class="field">
<%= f.label :first_name %><br />
<%= f.text_field :first_name%>
</div>
<div class="field">
<%= f.label :last_name %><br />
<%= f.text_field :last_name %>
</div>
<div class="field">
<%= f.label :company %><br />
<%= f.collection_select :company_id, #companies, :id, :name, prompt: true %>
</div>
<div class="field">
<%= f.label :role %><br />
<%= f.text_field :role %>
</div>
<div class="field">
<%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
<%= f.password_field :password, autocomplete: "new-password" %>
<% if #minimum_password_length %>
<br />
<em><%= #minimum_password_length %> characters minimum</em>
<% end %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "new-password" %>
</div>
<div class="actions">
<%= f.submit "Update" %>
</div>
<% end %>
I would like the updated information to be saved to the User database.
Currently, I get this error when I click update after changing the user info.
ActiveRecord::RecordNotFound in ManagerController#edit
Couldn't find User without an ID
Weirdly, when I see the User info, the url is: http://localhost:3000/users/edit?id=2
But when I update (and get the error), the url changes to: http://localhost:3000/users/edit.user
I would also like to be able to create New Users from this screen.
Currently, the user form populates with the information of the user who is logged in. (To be fair, I have been trying to get the edit user correct before tackling this issue.)
I think You want to update existing user info.
If that is the case:
I find your url path is wrong
:url => edit_user_registration_path(resource_name)
you donot have to user registration here .
If the admin going to update info
in routes file . some thing like this
namespace :admins do
resources :users
end
then use the path creatd from this
Many tries later, I've found a solution. There were a lot of errors, so bear with me.
Routes.rb -- Was using the wrong URL in the form submission, so needed to add the routes for the Update function in the Manager controller.
get 'users/edit' => 'manager#edit'
post 'users/edit' => 'manager#edit'
get 'users/update' => 'manager#update'
post 'users/update' => 'manager#update'
Manager Controller -- I had to change the password rules so that I could update without a password. Similar concept, slightly different execution.
def update
#user = User.find(params[:user][:id])
#companies = Company.all
if params[:user][:password].blank? && params[:user][:password_confirmation].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
end
if #user.update(user_params)
flash[:notice] = "Successfully updated User."
redirect_to root_path
else
render :action => 'edit'
end
end
Rendered Form.html.erb - Updated with newly created URL path.
<%= form_for(resource, as: #user, url: users_update_path(resource_name)) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>

Getting First argument in form cannot contain nil or be empty while trying to allow users to edit their password

I am trying to add a solution to allow users to change their password. I am using devise. And I followed up the third solution from this tutorial.
However after I do everything:
class UsersController < ApplicationController
before_action :authenticate_user!
def edit
#user = current_user
end
def update_password
#user = current_user
if #user.update_with_password(user_params)
# Sign in the user by passing validation in case their password changed
bypass_sign_in(#user)
redirect_to root_path
else
render "edit"
end
end
private
def user_params
# NOTE: Using `strong_parameters` gem
params.require(:user).permit(:password, :password_confirmation, :current_password)
end
end
in routes.rb
resource :user, only: [:edit] do
collection do
patch 'update_password'
end
end
and in the view:
<%= form_for(#user, :url => { :action => "update_password" } ) do |f| %>
<div class="field">
<%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password %>
</div>
<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 %>
but I get this error First argument in form cannot contain nil or be empty in
= form_for(#user, :url => { :action => 'update_password' } ) do |f|
is there something I have missed? Thanks!

My rails form keeps saying password can't be left blank after I try to sign up on my local server?

Every time I try to sign up on my rails form, it says password can not be left blank, and I am putting in a password every time. I've been staring at my code for hours now trying to figure it out, and I can't.
Here is my users/new.html.erb
<h1>Sign Up</h1>
<%= form_for #user do |f| %>
<% if #user.errors.any? %>
<div class="error_messages">
<h2>Form is invalid</h2>
<ul>
<% #user.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :email %><br />
<%= f.text_field :email %>
</div>
<div class="field">
<%= f.label :password %><br />
<%= f.password_field :password %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %>
</div>
<div class="actions"><%= f.submit "Sign Up" %></div>
<% end %>
Users controller:
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 root_url, notice: "Thank you for signing up!"
else
render "new"
end
end
private
def user_params
params.required(:user).permit(:name, :email, :password_digest)
end
end
User model:
class User < ActiveRecord::Base
has_secure_password
validates_uniqueness_of :email
end
Thanks for your help, I really am coming here as a last resort.
Change your user_params method to:
def user_params
params.required(:user).permit(:name, :email, :password)
end
Since you are dealing with password field/method I think you should allow it.
Add password to your parms.require method
i.e.
def user_params
params.required(:user).permit(:name, :email, :password)
end

sign up and create new object at the same time

i'm new in Ruby on Rails.
I was trying to register a new user with devise and at the same time, create a new Company object. The association between them : User belongs to Company. Company has many users. I tried to make it based on this link : http://railscasts.com/episodes/196-nested-model-form-part-1?view=asciicast, but it didnt work. it said : "undefined method for Company", which is Company doesnt have email attribute.
and in sign up form, i only put email attribute for user
<div class="title"><%= t('.signup') %></div>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div class="control-group"><%= f.label :email, t('.email') %>
<%= f.email_field :email %></div>
<div class="control-group"><%= f.label :password, t('.password') %>
<%= f.password_field :password %></div>
<div class="control-group"><%= f.label :password_confirmation, t('.password_confirmation') %>
<%= f.password_field :password_confirmation %></div>
<%= f.fields_for :company_attributes do |f_company| %>
<div class="control-group"><%= f_company.label :name, t('.company_name') %>
<%= f_company.text_field :name %></div>
<% end %>
<div class="buttons"><%= f.submit t('.signup'), class:"btn btn-primary" %><br>
<%= render "links" %></div>
<% end %>
updated
Company controller :
class CompaniesController < Devise::RegistrationsController
def new
#company = Company.new
#user = #company.users.build
end
def create
#company = Company.new(params[:company])
#user = User.create(params[:user].merge(company_id:company.id))
if #company.save
redirect_to "/"
else
render 'users/sign_up'
end
end
end
User Controller :
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
redirect_to users_path
else
render 'users/new'
end
end
I would really appreciate any idea and any help. Thanks in advance
In your case, since you are only interested in receiving the company_name I'd simplify it and submit the company_name via a text_field_tag.
In other words, I would replace:
<%= f.fields_for :company_attributes do |f_company| %>
<div class="control-group"><%= f_company.label :name, t('.company_name') %>
<%= f_company.text_field :name %></div>
<% end %>
With this
<%= text_field_tag 'company_name', {placeholder:"Enter here the name of your company",class:"form-control"} %>
This would submit the name to the UsersController, and you could access it with params[:company_name] so the controller would look like this:
Users controller:
def new
#user = User.new
end
def create
#user = User.create(params[:user])
#Create a company via 'user<->company' association using 'company_name'
#company= #user.company.create(name: params[:company_name])
if #user.save
redirect_to users_path
else
render 'users/new'
end
end

Resources