Rails validation problem - ruby-on-rails

I've got a User model with three fields, :email, :display_name and :handle. Handle is created behind the scenes from the :display_name.
I'm using the following validations:
validates :display_name, :presence => :true, :uniqueness => { :message => "Sorry, another user has already chosen that name."}, :on => :update
validates :email, :presence => :true, :uniqueness => { :message => "An account with that email already exists." }
I use the handle as the to_param in the model. If the user fails the validation by submitting a :display_name that already exists, then tries to change it and resubmit the form, Rails seems to use the new handle as the validation for the email -- in other words, it assumes that the email doesn't belong to the current user and validation on the email then fails. At this point, Rails assumes that the changed display name/handle is the one to use for the look up and the update action can't complete at all, because it can't find the user based on the new handle.
Here's the update method:
def update
#user = User.find_by_handle(params[:id])
#handle = params[:user][:display_name]
#user.handle = #handle.parameterize
...
end
This problem doesn't happen when the validation first fails on a duplicate email, so I'm assuming it's something about the way I've written the update method -- maybe I should try setting the handle in the model?

maybe I should try setting the handle in the model?
^ This.
The controller isn't the place to do something like this. If it's model logic that's happening behind the scenes, beyond the user's control, why put it in controller code?
Do it instead in a before_save filter, which is guaranteed to run only after the chosen display name is determined to be available and the record is deemed valid. In this way the handle won't be changed on the cached record until it is actually committed to the db, eliminating the problem of the incorrectly generated URL.
before_save :generate_handle
...
def generate_handle
self.handle = display_name.parameterize
end

Related

Make rails ignore inputs if user is admin

I have a user object, he can update his profile which includes name, user_name, password (blank), password_confirmation (blank), email, email_confirmation (blank), bio and picture url.
My model states that all of the (blank) MUST be filled in. but if your admin and your just going to the users page to update the user's role - You as the admin should not have to fill in user data you obviously don't know.
So how does one get around this? should I instead create a list of users with a drop down beside them? is this not, essentially , a giant form? If so - how would this get created?
essentially: What's the best way to deal with this situation?
This is currently how users get updated
def update
#user = User.friendly.find(params[:id])
#user.update_attributes(user_update_params)
if #user.save
render :show
else
render :edit
end
end
private
def user_update_params
params.require(:user).permit(:name, :user_name, :email, :email_confirmation, :password,
:password_confirmation, :bio, :picture_url, :role)
end
The real problem seems to be that you have a logical error in your User model validations.
You seem to have a validation of the form,
validates :password, presence: true, confirmation: true
which is enforced EVERY TIME, i.e. a new password has to be selected every single time a user object is saved. But this is likely not what you want. You likely want this validation to only be enforced when the user is created for the first time, i.e. when it is a new record.
You can do this with,
validates :password, presence: true, confirmation: true, if: :new_record?
update_attribute
Updates the attribute without doing validations, you need this one.
check out this api doc
EDIT:
Speaking about reading documentation
Here is an abstract from the method documentation
update_attribute(name, value) public
Updates a single attribute and saves the record. This is especially
useful for boolean flags on existing records. Also note that
Validation is skipped.
Callbacks are invoked.
updated_at/updated_on column is updated if that column is available.
Updates all the attributes that are dirty in this object.
EDIT:
If you still need to validate with this method, note that it says that callbacks are invoked, so what you can do is write your own code to validate input and use callbacks as described here.

How to customise devise views in rails 3.2 to include only some elements in the sign up form

I am a rails newbie and I have started hacking together a web app.
I used devise to set up user registrations and also generated the devise views templates.
I added custom models in there - username, first name, surname etc. I then added them in the attr_accessor in user.rb etc. and validates for the presence of these details
I thought of adding these elements in the edit registration form which worked successfully.
On the signup page - the code asks only for email, password, confirm password (as is set as default by devise).
If i now try and register as a new user (after all these steps), i get an error saying that First name cannot be empty, surname cannot be empty etc.
How can i exclude these from the sign up yet keep them active in the user profile edit?
I hope I'm making sense.thanks for your help in advance
If I understand correctly, during signup/registration you want to only ask for email and password, excluding the other User model attributes (first name, surname) from that form. However you also want to later have these other attributes validated when the user edits their profile.
So since you are validating for the presence of these extra attributes which are not provided when the signup form is submitted, the attempt to create a new user record simply fails to create at validation.
Try the :on => :update validation option to specify that certain fields should only be validated when later updated, rather than the default which is to validate any time a record is saved. Like this:
class User < ActiveRecord::Base
validates :email, :presence => true
validates :firstname, :presence => true, :on => :update
validates :surname, :presence => true, :on => :update
...
end
See http://guides.rubyonrails.org/active_record_validations_callbacks.html#on
you can go into your views > devise folder and create a registrations folder if its not there and make a new.html.erb
have a look at the file that you find under the link:
https://github.com/plataformatec/devise/blob/master/app/views/devise/registrations/new.html.erb
copy it to your new file and customize it as you want... it should overwrite the devise default view.

update_attribute/s() is calling callback for save password

I'm trying to update single attribute of a user model from a admin controller (not users controller).
While doing this I tried update_attribute() but it was changing the users password also.
I think the password is changing because I have before_save method on user model which hashes the password.
update_attributes() is not working because it is checking the validations for password which is presence=>true
Is there any way to achieve this?
You can set a condition on your validations by using the :if option. In my code, it looks something like this:
validates :password,
:length => { :minimum => 8 },
:confirmation => true,
:presence => true,
:if => :password_required?
def password_required?
crypted_password.blank? || password.present?
end
So basically, it's only if the crypted_password in the database is not set (meaning a new record is being created) or if a new password is being provided that the validations are run.
Try update_column(name, value), it might work.
You can update single attribute of user like this
#user is that user whose attribute you want to update
e.g user_name
#user.update_attributes(:user_name => "federe")
Try it and it will only update one attribute..
ActiveRecord has an 'update-column' method that skips both validations and callbacks:
http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update_column
However, I'd suggest that could be dangerous - you have that :before_save filter for a reason. If you place an :except method on the filter to circumvent in specific cases, it not only becomes reusable but you keep behaviour consistent and avoid having a method buried in a controller that's bypassing your Model's validation/callback stack.
I'm personally not overly keen on seeing methods like update_column anywhere except as protected methods inside Models.
Try :
To bypass callback and validations use :
User.update_all({:field_name => value},{:id => 1})
Just wanted to let you know :
In Rails, update_attribute method bypasses model validations, while update_attributes and update_attributes! will fail (return false or raise an exception, respectively) if a record you are trying to save is not valid.
The difference between two is update_attribute use save(false) where as update_attributes uses save or you can say save(true) .

Multiple validation error issue while saving a model in rails 3

I am having an issue while saving a user object in the database. I have two fields in the model (email and password) which are not allowed to be null in the database itself. Plus I have added validation in the model like
validates_presence_of :email, :message => "must be provided"
validates_presence_of :password, :message => "must be provided"
Now when I try to save the model from the create method of the controller, it invalidates the data and renders the new action again. However I have multiple error messages for each field
Email can't be blank
Email must be provided
Password can't be blank
Password must be provided
I don't need multiple error messages for the same one. How can I eliminate this?
Looks like you are validating in two different places. You have to figure it out the places...
If you are doing two different validation for a field and want to display one error message on a field at a time, you can do the following,
validates_presence_of :email, :message => "must be provided"
validates_uniqueness_of :email, :message => "must be unique",
:if => lambda { |a| a.errors.on(:email).blank? }
Looks like you are rendering errors twice. Check all your views, they can also be inherited.

Uniqueness constraint ruby on rails field

I am new to ROR and been trying to fumble my way through the tutorial by mike hartl( excellent read for starters i might add ). There is however something i am struggling with, my user model looks like below.
class User < ActiveRecord::Base
validates :name , :presence => true, :length => {:maximum => 50 }
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => true
end
I then open the ruby console using rails -c and create a new user
usr = User.new(:name=>"abcd",:email=>"svsvenu#gmail.com")
I then save it by using
usr.save
This created a new record in my database. So far so good.but if i type
usr.save
again, nothing happens, i look at the database ( sqlite ) and not even the last update date changed.
Another interesting thing i noticed is when i use
User.create(:name=>"abcd",:email=>"svsvenu#gmail.com"),
multiple times, there is a record created every time i run it in the console.
Can some one please explain why my save does not work and also why my uniqueness constraint is being ignored?
Thanks in advance
ActiveRecord is smart enough to understand that when you type usr.save twice in a row, the 2nd one is redundant.
usr = User.new
usr.save # usr is saved (if it was valid)
usr.save # usr is already saved and unchanged! do nothing.
usr.name = "bananas"
usr.save # usr name changed, commit the change!
When you say that a user is created in the console each time you run User.create, are you sure they're actually being created? In console you'll see a User returned each time, but the id would be nil if there had been errors in the create attempt. If you run create! instead you'd see an exception if the User had validation errors (like a duplicate email) and did not save.

Resources