Is this a good implementation of user_params strong parameter? - ruby-on-rails

def user_params
if current_user.admin?
params.require(:user).permit(:name, :email, :password, :student, :admin)
else
params.require(:user).permit(:name, :email, :password)
end
end
I would like admins to be able to update users' roles.
Users_params is a strong parameter to prevent hackers from changing users' roles.
The below code is insecure, correct? I see this code all over GitHub.
def user_params
params.require(:user).permit(:name, :email, :password, :student, :admin)
end

def user_params
if current_user.admin?
params.require(:user).permit!
else
params.require(:user).permit(:name, :email, :password)
end
end

Related

Devise not handling sanitized parameters

The following console information
Started POST "/users" for
Processing by RegistrationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"==", "user"=>{[...], "email_contact"=>"5#mail.ne", "cap"=>"", "client_retail"=>"true"}, "commit"=>"Register"}
Unpermitted parameters: :email_contact, :client_retail
is baffling, as the two unpermitted parameters (they were created subsequently to the original version, but the db was dropped, recreated and migrated) are stubbornly being ignored (while the user is getting created.
UsersController does include these attributes
def user_params
params.require(:user).permit(:email, :password, :password_confirmation, :remember_me, [...] :internal, :client_retail, :email_contact)
end
as does RegistrationsController:
private
def sign_up_params
params.require(:user).permit(:email, :password, :password_confirmation, :remember_me, [...] :internal, :client_retail, :email_contact)
end
def account_update_params
params.require(:user).permit(:email, :password, :password_confirmation, :remember_me, [...] :internal, :client_retail, :email_contact)
end
In addition, the ApplicationController invokes the sanitizer
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:email, :password, :password_confirmation, :nome, :cognome, :email_contact, :client_retail])
devise_parameter_sanitizer.permit(:sign_in, keys: [:login, :password, :password_confirmation])
devise_parameter_sanitizer.permit(:account_update, keys: [:email, :password, :password_confirmation, :current_password])
end
Oddly, those two attributes will get processed under the update action, although not listed in the sanitizer.
How can these parameters be allowed?
Rename your controller to Users::RegistrationsController < Devise::RegistrationsController or RegistrationsController < Devise::RegistrationsController depending on where your custom RegistrationsController is located.

how validation is done using wicked?

I have a users_controller and a user_steps_controller which has three steps :business, :payment and :login
In the user.rb model
class User < ActiveRecord::Base
validates_presence_of :fname, :lname, :email, :mob, :country, :state, :suburb, :postal ,:add
end
while checking validation if i put some random values then also it is giving errors
Fname can't be blank
Lname can't be blank
Email can't be blank
Mob can't be blank
Country can't be blank
State can't be blank
Suburb can't be blank
Postal can't be blank
Add can't be blank
Please help me out
This is my users_controller
def new
#user = User.new
end
def create
#user = User.new(params[:id])
if #user.save
session[:user_id]= #user.id
#user.update_attributes(user_params )
redirect_to user_steps_path
else
render :new
end
end
private
def user_params
params.require(:user).permit( :fname, :lname, :email, :mob, :gender_male, :gender_female, :country, :state, :suburb, :postal ,:add, :cmpyname, :abnacn, :cmpyadd, :cmpydet,:cash, :paypal,:bsb,:usrname,:password_hash, :password_salt, :selcat, :protit, :prodes)
end
user.rb
class User < ActiveRecord::Base
validates :fname, :lname, :email, :mob, :country, :state, :suburb, :postal ,:add, :presence => true
attr_accessor :current_step
validates_presence_of :cmpyname, :abnacn, :cmpyadd, :cmpydet, if: -> { current_step?(:business) }
validates_presence_of :usrname,:password_hash, :password_salt, :selcat, :protit, :prodes, if: -> { current_step?(:login) }
def current_step?(step_key)
current_step == step_key
end
end
user_steps_controller
class UserStepsController < ApplicationController
include Wicked::Wizard
steps :business, :login, :payment
def show
#user = current_user
render_wizard
end
def update
#user = current_user
params[:user][:current_step] = step
#user.update_attributes(user_params )
render_wizard #user
end
private
def user_params
params.require(:user).permit( :cmpyname, :abnacn, :cmpyadd, :cmpydet,:cash, :paypal,:bsb,:usrname,:password_hash, :password_salt, :selcat, :protit, :prodes)
end
end
user.rb
def current_step?(step_key)
current_step == step_key
end
user_steps_controller.rb
class UserStepsController < ApplicationController
include Wicked::Wizard
steps :personal, :social
def show
#user = current_user
render_wizard
end
def update
#user = current_user
params[:user][:current_step] = step
#user.attributes = user_params
render_wizard #user
end
private
def redirect_to_finish_wizard(options = nil)
redirect_to root_url, notice: "Thank you for signing up."
end
def user_params
params.require(:user).permit(:name, :current_step, :date_of_birth, :bio, :twitter_username, :github_username, :website)
end
end
This method will work for you.
Your real problem is here:
#user = User.new(params[:id])
I'm assuming params[:id] is nil, because otherwise that would fail. Basically, your instantiating a User with no data supplied and trying to save it. So clearly those validations you have supplied will fail. If you're actually submitting a form with user data you need to pass user_params you've already defined as follows:
#user = User.new(user_params)
If you need to have validations occur on your User model in different steps, you'll need to have the validations run conditionally dependent on the state of the form:
class User
attr_accessor :current_step
validates_presence_of :business_related_attr, if: -> { current_step?(:business) }
def current_step?(step_key)
current_step.blank? || current_step == step_key
end
end

Rails Devise - Add more number of attributes

I have been working on Devise and I tried to find a way to add more database attributes to the users table from devise. But it seems devise supports only email and password fields.
Is it possible to add more fields to the devise, so devise can validate to and save it to the users table on create, update calls.
yes you can add more fields by using migration.
I hope below link is help full to you.
http://www.jacopretorius.net/2014/03/adding-custom-fields-to-your-devise-user-model-in-rails-4.html
Yes. Checkout their documentation. https://github.com/plataformatec/devise
and search the page for "strong parameters" that should show you mostly what you're looking for.
an example:
class ApplicationController < ActionController::Base
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit({ roles: [] }, :email, :password, :password_confirmation, :first_name, :last_name, :gender, :avatar, :latitude, :longitude ) }
devise_parameter_sanitizer.for(:account_update) { |u| u.permit({ roles: [] }, :email, :password, :password_confirmation, :current_password, :first_name, :last_name, :age, :about_me, :gender, :avatar, :latitude, :longitude ) }
end
Yes you can like below I did for first_name, last_name
class RegistrationsController < Devise::RegistrationsController
private
def sign_up_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation)
end
def account_update_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation, :current_password)
end
end

Allowing only certain possible values in Rails Strong Parameters

I have a rails app with a user model, which is able to have several roles. I implemented this using a bitmask like this:
class User < ActiveRecord::Base
DEFAULT_ROLES = %w[developer entrepreneur]
ROLES = ['admin', 'entrepreneur', 'developer']
def has_role?(role)
roles.include?(role.to_s)
end
def is?(role)
has_role?(role)
end
def roles=(roles)
self.roles_mask = (roles & ROLES).map { |r| 2**ROLES.index(r) }.inject(0, :+)
end
def roles
ROLES.reject do |r|
((roles_mask.to_i || 0) & 2**ROLES.index(r)).zero?
end
end
end
In the signup page for the app, I want users to choose if they are an 'entrepreneur' or a 'developer'. However, I want to ensure that they are not able assign themselves (or anyone else) any other role, unless they are already an admin.
My first thought was to do this in the roles= method by changin it to look like
def roles=(roles)
unless current_user.is?(:admin)
validates_inclusion_of roles, :in => DEFAULT_ROLES
end
self.roles_mask = (roles & ROLES).map { |r| 2**ROLES.index(r) }.inject(0, :+)
end
However, as I found out, you can't access current_user from inside a model (which I guess makes sense if you think about it...)
My next attempt was to see if I could do this using Strong Parameters.
I was expecting it would look something like this (I'm using devise, overriding the RegistrationsController)
class RegistrationsController < Devise::RegistrationsController
private
def sign_up_params
if (user_signed_in?) && (current_user.is?(:admin))
params.require(:user).permit(:name, :school, :email, :password, :password_confirmation, {roles: User::ROLES})
else
params.require(:user).permit(:name, :school, :email, :password, :password_confirmation, {roles: User::DEFAULT_ROLES})
end
end
def account_update_params
if (user_signed_in?) && (current_user.is?(:admin))
params.require(:user).permit(:name, :school, :email, :password, :password_confirmation, :current_password, :about_me, {roles: User::ROLES})
else
params.require(:user).permit(:name, :school, :email, :password, :password_confirmation, :current_password)
end
end
end
However, when I tried that, I got this:
which makes me think I'm misunderstanding how Strong Parameters really works.
Is it possible to restrict what values a user can enter for any given field based on that users's role with Strong Parameters? If not, is there a different way to accomplish this?
I figured it out, here's how I did it. (This is the method overrides Devise's RegistrationController, if you're not using devise, then simply replace whatever method controls what parameters are entered into a new user.)
class RegistrationsController < Devise::RegistrationsController
private
def sign_up_params
parameters = params.require(:user).permit(:name, :school, :email, :password, :password_confirmation, :about_me, roles: [])
unless (user_signed_in?) && (current_user.is?(:admin))
parameters[:roles] = parameters[:roles].reject { |h| !User::DEFAULT_ROLES.include? h }
parameters
end
end
def account_update_params
if can? :assign_roles, :all
params.require(:user).permit(:name, :school, :email, :password, :password_confirmation, :current_password, :about_me, roles: [])
else
params.require(:user).permit(:name, :school, :email, :password, :password_confirmation, :current_password)
end
end
end
I just filtered out the parameter in parameters[:roles] to only include values that were contained in User::DEFAULT_ROLES (shown above in the question), and then returned the parameters object.

Devise strong parameters not working?

I have being following all the instructions from Devise github's but on sign up it is giving warning
WARNING: Can't mass-assign protected attributes for User: email, password, password_confirmation
here are my code snippets
RegistrationController
class RegistrationController < Devise::RegistrationsController
private
def account_update_params
params.require(:user).permit( :email, :password, :password_confirmation, :current_password)
end
def sign_up_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end

Resources