I have a Rails app with a user model that contains an admin attribute. It's locked down using attr_accessible. My model looks like this:
attr_accessible :name, :email, :other_email, :plant_id, :password, :password_confirmation
attr_accessible :name, :email, :other_email, :plant_id, :password, :password_confirmation, :admin, :as => :admin
And here's what my update method in my users controller looks like:
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:user], :as => current_user_role.to_sym)
flash[:notice] = "Profile updated"
redirect_to edit_user_url(#user)
else
render 'edit'
end
end
I have a helper method in my application controller that passes back the role as a string:
def current_user_role
#current_user_role ||= current_user.admin? ? "admin" : "default"
end
helper_method :current_user_role
I've also set config.active_record.whitelist_attributes = true in config/application.rb.
I've verified that the current_user_role method is returning the proper value based on the current user's admin status. Rails isn't throwing a mass-assignment error. But when I try to update a user's admin status while logged in as an admin, Rails performs the update and silently ignores the admin attribute. Pulling up the user's record in the Rails console shows that the record hasn't been modified.
I have a feeling there's a Ruby- or Rails-specific issue at play that I'm not aware of. I can't locate any info on making the role dynamic. The best I could find was this.
There was an errant attr_accessor :admin in my model that was left in from a prior attempt at getting this to work. I overlooked it. Removing it fixed it.
So, the upshot is that this is a pretty simple way to get dynamic roles working in Rails 3.2.
Looks like it could be a bug in Rails 3.2
https://github.com/stffn/declarative_authorization/issues/127
Related
First of all, I believe there must be some people, who already asked this question before but I don't know how can I google this problem. So, if it is duplicate I am sorry.
I am working on a social media site. I have user model, which I use to register users to the site. It validates, name, email, and password when registering.
I use the same model to make users edit their informations, like username.
This is what I have in my update controller:
def update
# Find an existing object using form parameters
#profile = User.find_by_id(current_user.id)
# Update the object
if #profile.update_attributes!(settings_profile_params)
# If save succeeds, redirect to itself
redirect_to request.referrer
else
# If save fails, redisplay the form so user can fix the problems
render('edit')
end
end
private # user_params is not an action, that is why it is private.
def settings_profile_params
params.require(:user).permit(:first_name, :last_name, :username, :school, :program, :website, :information)
end
The problem is, I only want to update strong parameters that I defined there. But I am getting an exception because of password validation. I don't know why am I getting this exception. How can I set up system to update the values in strong parameter only.
Thank you.
You can achieve this by changing you password validation. You need to add a condition on password validation.
# Password
validates :password,
:presence => {:message => 'Password cannot be blank'},
:length => {:within => 8..99, :message => 'Password length should be within 8 and 99 characters'}
:if => Proc.new { new_record? || !password.nil? }
By calling update_attributes you are implicitly invoking the same range of validations as an other update and save. You need to update on the specific params you're targeting (e.g. omitting :password).
Here, we can store that list of permitted keys in a variable that is reusable. Then we call update_attribute on each of those keys — doing so within a reduce that gives the same true/false for the switch to edit or display.
def update
# Find an existing object using form parameters
#profile = User.find_by_id(current_user.id)
# Update the object
if PERMITTED_KEYS.reduce(true) {|bool, key| bool &&= #profile.update_attribute(key, #profile.send(key)) }
# If save succeeds, redirect to itself
redirect_to request.referrer
else
# If save fails, redisplay the form so user can fix the problems
render('edit')
end
end
private
PERMITTED_KEYS = [:first_name, :last_name, :username, :school, :program, :website, :information]
# user_params is not an action, that is why it is private.
def settings_profile_params
params.require(:user).permit(PERMITTED_KEYS)
end
Having not used strong_parameters gem before, I think this would be more idiomatic to the use of the gem:
def update
# Find an existing object using form parameters
#profile = User.find_by_id(current_user.id)
# Update the object
if settings_profile_params.keys.reduce(true) {|bool, key| bool &&= #profile.update_attribute(key, #profile.send(key)) }
# If save succeeds, redirect to itself
redirect_to request.referrer
else
# If save fails, redisplay the form so user can fix the problems
render('edit')
end
end
private
# user_params is not an action, that is why it is private.
def settings_profile_params
params.require(:user).permit(
:first_name, :last_name, :username,
:school, :program,
:website, :information
)
end
Though, I still think this is a duplicate question, since it regard how to update model data without all of the defined validation. I've answered in case the update_attributes loop is felt to be a sufficiently unique solution to warrant non-duplication.
Okay, now I found the problem. First of all, #Muntasim figured out a way to solve this problem. But I actually don't need to use this solution, because there is another easy way to fix this.
In this situation, when I let users to update their profiles, rails should not validate my password or any other column in user model, if I don't ask it to. But why was it validating? Because I have validates :password in user model. Instead it has to be validates :digest_password. Because I am using bcrypt.
I don't know why :password was working fine when I register even though I used bcrypt.
So, I'm trying to implement simple role based authentication system using Rails and I'm having a problem with final step - changing roles.
role is attribute in user table and it has a string type.
Idea is that some users with some privilages have ability to change roles.
Code in view looks like this:
<div>
<%= f.label :role, 'Role' %>
<%= f.collection_select :role, User::ROLES, :to_s, :humanize,
prompt: 'Select role' %>
</div>
update method in users_controller looks like this:
def update
#user = User.find(params[:id])
if #user.update(update_params) #update_params is method that returns permitted parameters
redirect_to #user
else
render :edit
end
end
Problem is that user[role] is empty after submitting a form.
Everything is pretty much made "by the book". Also, I am using Cancan but it's turned off for edit and update with load_and_authorize_resource :except => [:update, :edit].
So, I've found a solution. Since I'm using CanCan and user_params method so CanCan itself can set permitted parameters, my update_params method is ignored.
Solution is to add :role to user_params method.
So I've gone through the Rails tutorial here:
http://ruby.railstutorial.org/ruby-on-rails-tutorial-book
and am trying to get ActiveAdmin to be able to delete Users. Via the tutorial, my User model has_secure_password and also has a remember_token attribute. Consequently, when I go to my ActiveAdmin Users page and try to edit a User, the fields that are to be filled in are: Username, Email, Password Digest, Remember Token.
When I, for instance, modify the name field and try to submit the edit request, I get a ActiveModel::ForbiddenAttributesError. This happens when I try to create a User as well. I'm thinking this obviously has something to do with my authentication/password setup, but being fairly new to Rails, I'm not sure where to start looking. Any ideas?
EDIT: I tried adding this to my app/admin/user.rb file:
controller do
def resource_params
return [] if request.get?
[ params.require(:active).permit(:name, :email, :password_digest, :remember_token) ]
end
end
and this error in my stack trace disappears:
Unpermitted parameters: utf8, _method, authenticity_token, commit, id
Now, when I hit update within ActiveAdmin, I no longer get a ForbiddenAttributesError. Instead, the page reloads, but the changes aren't committed, and I get this message in my terminal:
Started PATCH "/admin/users/59" for ...
...
...
(0.1ms) begin transaction
User Exists (0.5ms) SELECT 1 AS one FROM "users" WHERE (LOWER("users"."email") = LOWER('example-58#railstutorial.org') AND "users"."id" != 59) LIMIT 1
(0.2ms) rollback transaction
This is my users_controller.rb:
def update
#active = Active.find(params[:id])
if #active.update_attributes(active_params)
flash[:success] = "Profile updated"
redirect_to #active
else
render 'edit'
end
end
private
def active_params
return [] if request.get?
[ params.require(:active).permit(:name, :email, :password_digest, :remember_token) ]
end
I don't know ActiveAdmin specifically, but your error says you're not permitting your id param
Params
You've got your params like this:
params.permit user: [:name, :email, :password_digest, :remember_token ]
I'd start by trying this:
params.require(:user).permit(:name, :email, :password_digest, :remember_token)
ActiveAdmin
How to get ActiveAdmin to work with Strong Parameters?
According to this question, you'll need to look at the official documentation and may be able to try this:
config.before_filter do
params.permit!
end
This is an existing problem with Active Admin: https://github.com/gregbell/active_admin/issues/2595
Which is a symptom of setting:
config.action_controller.action_on_unpermitted_parameters = :raise
I don't know of a solution as of yet, and as you can see no one has commented on that ticket. The most expedient option would be not to :raise on unpermitted parameters, but to use the default behavior of skipping over them.
User.rb for ActiveAdmin example
In this case, User has_one :account
ActiveAdmin.register User do
config.batch_actions = false
# Your params here
permit_params :first_name, :last_name, :email,
:born_date, :password, :password_confirmation, :account,
account_attributes: [:country_id,:university_id, :english_level]
# stuff
end
i have a problem in ruby on rails. I want to make current user's store id to be 0 when user accesses to /homepage/, and i want to make user's store id to be the input id in the url when user accesses to /homepage/:id/.
My code:
routes.rb:
match "/homepage" => "users#access", :as => "store"
match "/homepage/:id" => "users#homepage", :as => "store"
def access
#user = current_user
#user.update_attributes(:store => "0")
#user.save
end
def homepagestore
#user = current_user
#user.update_attribute(:id, user.store = :id)
#user.save
end
update_attribute updates the record in the database. But it skips the validation checks. update_attributes also updates (saves) the record in the database. It does not skip validation.
So:
You should use params[:id] as Sergio says
You may want to use update_attributes instead since it does not skip validation checks
You do NOT need the save method if you use update_attribute or update_attributes
My suggestions:
def access
#user = current_user
#user.update_attributes(:store => "0")
end
def homepagestore
#user = current_user
#user.update_attributes(:store => params[:id])
end
Added update_attributes uses the mass-assignment protection system. So you need the :store field in your User model's attr_accessible call to allow it to be changed. Or override the protection, see the update_attributes docs. Ask if you have more questions.
I'm having this problem, I tried a lot of differents aproachs but
everytime it falls in that error.
Enviroment:
Rails 3.0.5
Mongoid 2.0.1
class User
include Mongoid::Document
field :name
has_and_belongs_to_many :companies
end
class Company
include Mongoid::Document
field :name
has_and_belongs_to_many :users
end
In my UserController method Create a I do something like this:
#user = User.where(:email => params[:user][:email])
if #user.count > 0
#user.companies.push(#company)
#user.save
#company.users.push(#user)
#company.save
else
#user = User.create(:name => params[:user][:name],
:email => params[:user][:email],
:password => "123456")
#user.companies.push(#company)
#user.save
#company.users.push(#user)
#company.save
end
When the user dont exist works great.
But if the user is already in the DB, fall a error.
NoMethodError in UserController#create
undefined method `companies' for #<Array:0x10679f638>
But after all it pushes the object into the document.
I don't know if I'm missing something.
If someone know how to solve this ... will be great.
Thanks in advance.
Try this:
#user = User.where(:email => params[:user][:email]).first
On a side note, you may also want to push some of this code into one of your models, either the User or Company model, so that in your controller you would only have one call such as:
#company.add_user(#user)
The implementation details of adding a user would then be encapsulated in your model.
You may also want to consider embedding the two calls to ActiveRecord::Base#save into a single transaction to avoid ending up with inconsistent data in your database.