Limiting which user attributes can be updated - ruby-on-rails

I do not want to allow the user to update their :name. I found this question for Rails version 3 but the answer does not work for me. I am using Rails 4. I might just have the wrong syntax. I couldn't get #user.update_attributes(params[:user]) to work. Only: #user.update_attributes(user_params). I am not including :name on my edit form, but my understanding (??) is that a user could still pass it through the browser themselves and with my current code they could change :name.
class UsersController < ApplicationController
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
#user.update_attributes(user_params)
if #user.save
flash[:success] = "Profile updated"
redirect_to #user
else
flash[:danger] = "Profile update Unsuccessful"
redirect_to 'edit'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :email_confirmation, :password, :password_confirmation)
end

There's more than one way to assure users won't tamper with your business rules.
As you're already using Rails 4, you can take advantage of strong parameters to deny access to the :name attribute.
You can have different sets of rules for each controller action:
def create_user_params
params.require(:user).permit(:name,:email, :email_confirmation, :password, :password_confirmation)
end
def update_user_params
params.require(:user).permit(:email, :email_confirmation, :password, :password_confirmation)
end
#user.create(create_user_params)
#user.update_attributes(update_user_params)
drying up:
def allowed_update_attrs
[:email, :email_confirmation, :password, :password_confirmation]
end
def allowed_create_attrs
allowed_update_attrs + [:name]
end
def user_params
params.require(:user)
end
#user.create user_params.permit(*allowed_create_attrs)
#user.update_attributes user_params.permit(*allowed_update_attrs)
There are other ways of accomplishing the same thing like tapping into already permitted attributes, but this way seemed simpler.

Related

Difficulty in implementing a one to one relationship

I am trying to update the profile of a user, however, I am getting an ArgumentError (wrong number of arguments (given 6, expected 1)): The relation between the user model and user profile model is one-to-one
application_controllers.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
helper_method :current_user, :logged_in?
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
end
def create
#user_profile = UserProfile.new(user_profile_params)
#user_profile.user_id = current_user.id
if #user_profile.save
format.html {redirect_to home_index_path, notice:"Account created successfully" }
else
flash.now.alert = "Oops, couldn't create account. Please make sure you are using a valid email and password and try again."
format.html { render :new }
end
end
private
def user_profile_params
params.require(:first_name, :other_name, :last_name, :phonemumber, :email, :seller_id)
end
Problem is on this line:
def user_profile_params
params.require(:first_name, :other_name, :last_name, :phonemumber, :email, :seller_id)
end
You should use either:
def user_profile_params
params.require(:user_profile).permit(:first_name, :other_name, :last_name, :phonemumber, :email, :seller_id)
end
or
def user_profile_params
params.permit(:first_name, :other_name, :last_name, :phonemumber, :email, :seller_id)
end
Depends on data you are getting from the form. And btw. there is a typo in :phonemumber should probably be :phonenumber.

CanCanCan: How to handle an object that is nil in Ability model?

I have this controller:
class UsersController < ApplicationController
load_and_authorize_resource
def create
#user.save
respond_with #user
end
def update
#user.update user_params
respond_with #user
end
def destroy
#user.destroy
respond_with #user
end
private
def user_params
permitted_keys = [:name,
:email,
:password,
:password_confirmation,
:lock_version]
permitted_keys << :role if can? :edit_role, #user
params.require(:user).permit(permitted_keys)
end
end
In my ability model:
can :edit_role, User do |user|
user.new_record?
end
The problem is, that when creating a user (#new or #create action), #user is nil. So the role can't be set, as it will not be added to the permitted_keys on #create.
How can this be solved? I could change my controller to:
permitted_keys << :role if action_name == 'create'
But I don't like this, as the Ability can be tested much more easily than this.
Another workaround would be this:
permitted_keys << :role if can? :edit_role, #user || User.new
But this feels redundant.
Anybody has a better idea? And by the way - I'm quite surprised that passing nil as object to can? is allowed and doesn't raise an error. It seems that it doesn't even propagate to the actual configuration in Ability, as otherwise user.new_record? would raise a NoMethod error or similar.
The CanCan docs prescribe defining abilities with blocks a little differently than how you've done it. They suggest using a guard instead of a block for the case you described (when the instance is nil):
# don't do this
can :edit_role, User do |user|
user.new_record? # this won't be called for User.accessible_by(current_ability, :edit_role)
end
# do this
can :edit_role, User if user.new_record?
I'd try this. For other information and to see where I got this example, check these docs
It seems that using CanCanCan gem, the user_params method is called before the #user variable is created; this kind of makes sense, as user_params is needed to create the #user variable, or at least it is needed to assign the values from the form.
If CanCanCan would assign a new #user variable (of type User, of course) before assigning the values from the form, the following code would work on #create:
private
def user_params
permitted_keys = [:name,
:email,
:password,
:password_confirmation]
permitted_keys << :role if can? :edit_role, #user
permitted_keys << :disabled if can? :disable_user, #user
params.require(:user).permit permitted_keys
end
But as it doesn't do that apparently, the following workaround works for me:
private
def user_params
permitted_keys = [:name,
:email,
:password,
:password_confirmation]
auth_object = #user || User.new
permitted_keys << :role if can? :edit_role, auth_object
permitted_keys << :disabled if can? :disable_user, auth_object
params.require(:user).permit permitted_keys
end

Ruby on rails new object properties

i need to add to my user new objet some new properties that i will define when the form is submited by retrieve them from my database, but when i submited the new properties are nill and i dont know why
def create
plan = params[:user][:plan]
#plan_vars = Plan.find(plan)
#user = User.new(user_params, :plan_id => #plan_vars.id, :lessons => #plan_vars.lessons)
if #user.save
flash[:success] = "Usuario creado exitosamente"
redirect_to users_path
else
flash[:warning] = "Ooops... algo ha fallado :O #{#user.errors}"
redirect_to new_user_path
end
end
here is the user params
def user_params
params.require(:user).permit(:name, :email, :phone, :document, :password,
:password_confirmation)
end
Here is what to do?
Do this:
#user = User.new(user_params)
#user.plan_id = #plan_vars.id
#user.lessons = #plan_vars.lessons
#user.save
if nested form is used or #plan_vars returns array there results another type of error
You can merge plan params to user_params hash
def user_params
params.require(:user).permit(:name, :email, :phone, :document, :password,
:password_confirmation)
.merge(plan_id: #plan_vars.id, lessons: #plan_vars.lessons)
end
def create
plan = params[:user][:plan]
#plan_vars = Plan.find(plan)
#user = User.new(user_params)
end
Hope, that helps!
I prefer something similar to #Lavika's answer, but with merge on create action
def create
plan = params[:user][:plan]
#plan_vars = Plan.find(plan)
#user = User.new(user_params.merge(plan_id: #plan_vars.id, lessons: #plan_vars.lessons))
# ...
end
#pradeep sapkota's answer is also a good option

Allowing users to edit some information only on ruby on rails but not admins

I'm working on a rails app that i want to allow users to edit only some of their information, like name or personal information, but i want the admin user to be able to edit every thing. is there any one to help me with this?
thanks to #tadman this is what i came up with
def user_params_UserEdit
if current_user?(#user)
params.require(:user).permit( :password,
:password_confirmation)
elsif current_user.admin?
params.require(:user).permit(:name, :email, :password,
:password_confirmation, :admin, :personel_number)
end
end
and for update :
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params_UserEdit)
flash[:success] = "Profile updated"
redirect_to root_url
else
render 'edit'
end
end
it works fine with me what do you think?
You can use cancan feature for this purpose. It's clean and provides many features to add/modify the permissions.
Have a look
https://github.com/ryanb/cancan
Also there is a tutorial on how to use it
http://railscasts.com/episodes/192-authorization-with-cancan

How to create new User with an Organization association

In my webapp my User Signup page has an Organization Name field. I have an Organization model that has_many :users, and my User model belongs_to :organization. When a new user is created, I'd like for the Organization Name value to be used to create a new organization record, and associate it with the user, such that user.organization_id = the new organization id.
This is my users_controller.rb code:
class UsersController < ApplicationController
def new
#user = User.new
end
def show
#user = User.find(params[:id])
#organization = Organization.find(#user.organization_id)
end
def create
#organization = Organization.new(organization_params)
#user = User.new(user_params)
if #user.save && #organization.save
sign_in #user
redirect_to #user
flash[:success] = "Welcome to the App!"
else
flash.now[:danger] = "Uh oh, there's been an error"
render 'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
def organization_params
params.require(:organization).permit(:name)
end
end
Right now both the user record and organization record are being created when a user submits the signup form, but the association is not saved. The user.organization_id value is nil.
Can you comment on what's wrong, and if there's a good way to do what I'm going for -- maybe with .build?
Thanks!
Brennan
Yes! .build will work, but because its a single association back, you will be using the association name in your build command, ie build_organization
def create
#user = User.new(user_params)
#user.build_organization(organization_params)
if #user.save
blah blah blah
You only need to save the user (not #organization) if done this way because the association is taken care of.
At user_params permit :organization_id ;)
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation, :organization_id)
end
EDIT: You also need to set organization_id somewhere for user - if you're not doing it in form (like with select or some else field) you can use .build method.

Resources