ActiveAdmin change password inside app - ruby-on-rails-4

I went off the Devise Page so that users can change their password inside ActiveAdmin. The method 3 doesn't work as is, so I had to modify it a bit for ActiveAdmin
ActiveAdmin.register_page 'UserPassword' do
def user_params
params.required(:user).permit(:password, :password_confirmation)
end
page_action :update_password, method: :post do
#user = AdminUser.find(current_admin_user.id)
if #user.update(params.required(:user).permit(:password, :password_confirmation))
# Sign in the user by passing validation in case their password changed
sign_in #user, :bypass => true
redirect_to admin_root_path, notice: "Your password was changed"
else
redirect_to admin_userpassword_path, alert: "Your password couldn't be changed"
end
end
content do
render partial: 'edit', locals: {user: current_admin_user}
end
end
I had to change if #user.update(params.required(:user).permit(:password, :password_confirmation)) because if (#user.update(user_params)) would throw an error saying undefined local variable or method user_params
is the code I have listed above the correct approach to being able to let users change their passwords inside the ActiveAdmin layout?

I would register the User model as a resource in ActiveAdmin. Then you can use the form block to create a form, where the use can change the password.
ActiveAdmin.register User do
...
form do |f|
inputs 'Details' do
input :password
input :password_confirmation
end
actions
end
...
end

Related

Rails 4 build_association

in my rails 4 app, i have a user model that has_one profile model which also belongs_to the user model
this is my first time using a nested resource so im kinda lost to it
here how it goes
, a user creates an account,after succesful email authentication , user proceed to create a profile. Problem is, im getting error on using the build_association. Im not sure whether the problem is actually that or im getting null values on the params(which i think not)
in my routes.rb
resources :users do
resources :profiles
end
profiles view, new.html.erb
<%= form_for(#profile,url:{ :controller => 'profiles', :action => 'create'},html: {class: "ui large segment form error"}) do |f| %>
<%= render 'shared/form_error_messages', object: f.object%>
<div class="ui horizontal divider">Create a Profile</div>
<%= f.text_field :first_name, :placeholder => "First Name" , :required => true%>
<%= f.submit "Submit Profile", class: "ui submit button"%>
<% end %>
profiles_controller.rb
def new
#user = User.find(params[:user_id])
#profile = #user.build_profile
end
def create
#profile = #user.build_profile(profile_params)
if #profile.save
flash[:success] = "Profile has been created"
redirect_to root_url
else
render 'new'
end
end
private
def profile_params
params.require(:profile).permit(:first_name)
end
when im submitting the form, im getting
NoMethodError in ProfilesController#create
undefined method `build_profile' for nil:NilClass
Application Trace | Framework Trace | Full Trace
app/controllers/profiles_controller.rb:9:in `create'
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"MFCANYra..",
"profile"=>{"first_name"=>"sample",
"commit"=>"Submit Profile",
"user_id"=>"1"}
Try changing the create action in profiles_controller.rb as below :-
def create
#user = User.find(params[:profile][:user_id])
#profile = #user.build_profile(profile_params)
if #profile.save
flash[:success] = "Profile has been created"
redirect_to root_url
else
render 'new'
end
end
let me know this worked or not, try to find if something else is causing the problem, thanks.

By Pass Devise Password requirement for single attribute update

Currently my application is using devise and my users are required to enter a password when updating their profile.
I am working on implementing an additional field to my user's table which remembers their sidebar navigational preference (expanded or collapsed). For testing, I setup a boolean field called "menu_collapsed" which is set to "false" by default.
I am trying to have this value updated to "true" remotely when the user decides to condense the sidebar menu.
Index
<li><%= link_to('Toggle', toggle_menu_preference_user_path(#user), :method => :put) %></li>
Routes
resources :users do
member { put :toggle_menu_preference }
end
Users Controller
def toggle_menu_preference
#user = current_user
#user.menu_collapsed = !#user.menu_collapsed
#user.save
end
Application Controller
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:first_name, :last_name, :email, :account_id, :account_name, :password, :password_confirmation) }
devise_parameter_sanitizer.for(:account_update).concat([:name])
end
When I click on the link, it will process the request but I hit a wall with Devise wanting the user to include their password.
Is there a way to by pass the requirement for a password just for this user attribute?
This seems to work like a charm!
Tested on local host as well as Heroku
Application Controller (added :menu_collapsed) to sanitizer
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:first_name, :last_name, :email, :account_id, :account_name, :password, :password_confirmation) }
devise_parameter_sanitizer.for(:account_update).concat([:name, :menu_collapsed])
end
Routes
resources :users do
member { put :toggle_menu_preference }
end
User Controller
def menu_preference
#user = current_user
#user.menu_collapsed = !#user.menu_collapsed
#user.save
if #user.menu_collapsed
render :nothing => true
else
render :nothing => true
end
end
View
<%= link_to menu_preference_user_path(current_user), id: "layout-condensed-toggle", remote: true do %>
<div class="iconset top-menu-toggle-dark"></div>
<% end %>

Testing custom devise registration controller update action with Rspec

I followed this devise wiki documentation on how to write a custom update action for the registration controller when you want to allow users to edit their account without providing their passwords except if changing their passwords themselves.
Devise Wiki - How to Allow Users to Edit Account Without Providing a Password.
However, I can't figure out what's missing in my Rspec test to make it pass. Here are the relevant code snippets:
app/controllers/registrations_controller.rb
def update
#user = User.find(current_user.id)
successfully_updated = if needs_password?(#user, params)
#user.update_with_password(devise_parameter_sanitizer.sanitize(:account_update))
else
# remove the virtual current_password attribute
# update_without_password doesn't know how to ignore it
params[:user].delete(:current_password)
#user.update_without_password(devise_parameter_sanitizer.sanitize(:account_update))
end
if successfully_updated
set_flash_message :notice, :updated
# Sign in the user bypassing validation in case their password changed
sign_in #user, :bypass => true
redirect_to users_path
else
render "edit"
end
end
spec/factories/users.rb
FactoryGirl.define do
factory :user do
email { Faker::Internet.email }
password 'XXXXXXXXX'
first_name { Faker::Name.first_name }
middle_name { Faker::Name.first_name }
last_name { Faker::Name.last_name }
end
end
spec/controllers/registrations_controller_spec.rb
describe "PUT #update" do
login_pcp
let(:user) { FactoryGirl.create(:user, first_name: 'Tom') }
it "changes user attributes" do
attrs = FactoryGirl.attributes_for(:user, first_name: 'Jerry')
attrs.delete(:password)
put :update, user: attrs
user.reload
assigns[:user].should_not be_new_record
expect(user.first_name).to eq 'Jerry'
expect(flash[:notice]).to eq 'You updated your account successfully.'
end
end
When I run the spec I get the following error:
Failures:
1) RegistrationsController PUT #update changes user attributes
Failure/Error: expect(user.first_name).to eq 'Jerry'
expected: "Jerry"
got: "Tom"
(compared using ==)
# ./spec/controllers/registrations_controller_spec.rb:55:in `block (3 levels) in <top (required)>'
For some reason, it's not saving the update. I'm not sure if a password should be entered in order for the update to take place? Any help would be appreciated. Thanks!
The test now looks like this and it passes:
describe "PUT #update" do
before :each do
#request.env['devise.mapping'] = Devise.mappings[:user]
user_tom = FactoryGirl.create(:user, email: 'tom#test.com')
sign_in user_tom
end
it "changes user attributes" do
put :update, user: { email: 'jerry#test.com' }
subject.current_user.reload
assigns[:user].should_not be_new_record
expect(subject.current_user.email).to eq 'jerry#test.com'
expect(flash[:notice]).to eq 'You updated your account successfully.'
end
end
I ran into this issue as well, but as I can see it's because when you fill the update form, you will be required to fill in a field called "Current password". Since the data won't be updated unless you fill in the filed. When you use factory girl to produce user data, there is no this value. I solved it as can be seen in following code.
describe "PATCH #UPDATE" do
before :each do
#user = create(:user)
#old_email = #user.email
sign_in #user
end
context 'valid attributes' do
it "updates user attributes" do
patch :update, id: #user,
user: attributes_for(:user, current_password: "password")
expect(#user.reload.email).not_to eq(#old_email)
end
end
end

Adding an editable field to omniauth generated / existing user

I'm using omniauth-twitter to create and authenticate users in my rails app and I'm successfully getting everything I need from Twitter, avatar, username, description, etc. But I'd like to let users add a custom string to display on their account page.
I added a column to the User table and ran the migration. The column is there.
I can't seem to get the update form to work, however. I'm not seeing errors. I just get a page refresh. Since I didn't have an existing form or controller methods to begin with I added them manually.
Here's my Users controller (I'm using friendly-id, hope that doesn't throw you.)
class UsersController < ApplicationController
def index
#users = User.all
end
def show
#user = User.friendly.find(params[:id])if params[:id]
end
def edit
#user = User.friendly.find(params[:id])if params[:id]
end
def update
#user = User.friendly.find(params[:id])if params[:id]
end
private
def user_params
params.require(:user).permit(:custom_text)
end
end
I'm not sure if I need both edit and update methods here, but I thought I'd try.
Here's my form (SLIM Template) which I include on the user's show page:
= form_for #user do |f|
= f.text_field :custom_text
= f.submit
The submit button works, as it were, but nothing is updated.
I'm pretty sure I'm just overlooking something painfully obvious.
I can't seem to get the update form to work, however. I'm not seeing errors.
Nothing is getting updated because you are not updating anything in the first place. As per the current code in the update action, its just selecting the record to be updated from the database but doing nothing with it.
def update
#user = User.friendly.find(params[:id])if params[:id] ## Simply selecting
end
In order to update the fetched record, you should call either update or update_attributes method on the instance of User model passing the changed attributes values to the method.
SOLUTION:
Use the following updated code in your UsersController. I have also DRYed up the code little bit by adding a before_action callback named set_user. The set_user method will be called every time before performing the actions such as show, edit and update and will take care of setting the instance variable #user.
class UsersController < ApplicationController
## Adding a before action callback
before_action :set_user, only: [:show, :edit, :update]
def index
#users = User.all
end
def show
end
def edit
end
def update
if #user.update(user_params)
## Redirect to user show page on successful update
redirect_to #user, notice: 'User was successfully updated.'
else
## Render user edit page again upon failure to update
render action: 'edit'
end
end
private
def set_user
#user = User.friendly.find(params[:id]) if params[:id]
end
def user_params
params.require(:user).permit(:custom_text)
end
end
Have you tried changing your form code to set the multipart:true to allow file to be sent
Try this and then upload the photo
= form_for #user,html: {multipart: true} do |f|
= f.file_field :custom_photo
= f.submit
I might also be missing something painfully obvious or new in Rails 4, but it seems like you should actually be telling the DB to update your record:
def update
#user = User.friendly.find(params[:id]) if params[:id]
#user.update_attributes(user_params) if #user
end
private
def user_params
params.require(:user).permit(:custom_text)
end
Without this second line in the update action, it's just finding the record and not doing anything with it...

create in rails 4 active admin

I have a user model and inside active admin i have written like
ActiveAdmin.register User do
controller do
def permitted_params
params.require(:user).permit(:username,:email,:password,:password_confirmation,
:admin, :locked, :first_name, :last_name, :work_phone, :cell_phone,
:cell_carrier, :fax, :temp_password,
:active, :company_id, :group_id, role_ids:[])
end
def create
#user = User.new(params[:user])
if #user.save
redirect_to admin_users_path
else
render :new
end
end
end
end
But when ever i am trying to create the user its showing an error like. ActiveModel::ForbiddenAttributesError - ActiveModel::ForbiddenAttributesError:
What i am doing wrong ?
Inherited Resources is a little weird with permitted params. You don't actually get to require key. You have to pass a hash to the permit method.
If you're using the latest version of ActiveAdmin, you should also be able to use the permit_params method.
ActiveAdmin.register User do
permit_params :username, :email, :password, :password_confirmation,
:admin, :locked, :first_name, :last_name, :work_phone, :cell_phone,
:cell_carrier, :fax, :temp_password,
:active, :company_id, :group_id, role_ids:[]
end
end
Also, if you are going to override the create method, you must use permitted_params in place of params[:user], which is most likely the cause of the current error you're getting. It doesn't look like you're actually doing anything special in your custom create action, though, so unless you plan to do something more, you should probably just let ActiveAdmin handle the controller actions.