Validates attributes that aren't even being changed

I have a form where I can only update the user’s first name, last name
and email address.

I have this in the user model file, user.rb

validates :username,
:presence => true,
:uniqueness => true,
:on => :update

validates :password,
:presence => true,
:length => { :minimum => 6, :maximum => 20},
:confirmation => true,
:on => :update

But everytime I try to change the user’s first name, I get the error
messages that the username is already taken and such. I’m not even
trying to update the username. And there is NOT EVEN A FIELD for the
username in the form.

When I try to update the user’s first name in the console, I get the
same errors.

How can I make Rails NOT run that validation when I’m trying to update
other fields?

On Thu, Aug 11, 2011 at 2:58 PM, Leonel . [email protected]
wrote:

I have this in the user model file, user.rb

validates :username,
:presence => true,
:uniqueness => true,
:on => :update

But everytime I try to change the user’s first name, I get the error
messages that the username is already taken and such.

How can I make Rails NOT run that validation when I’m trying to update
other fields?

Seriously?

How about removing the " :on => :update " where you’re telling Rails
you do want to run it then?

Just a thought… :slight_smile:


Hassan S. ------------------------ [email protected]

twitter: @hassan

Well yeah but even if I take :on => :update away it’ll still run the
validation, right?

I’ve read that Rails runs the validation on “update” and “save” unless
you specify otherwise.

On Thu, Aug 11, 2011 at 4:02 PM, Leonel . [email protected]
wrote:

Well yeah but even if I take :on => :update away it’ll still run the
validation, right?

Easiest way to find out is to try it :slight_smile:

I’ve read that Rails runs the validation on “update” and “save” unless
you specify otherwise.

If so, then do just that, e.g. ’ :except => :update ’

Or so I would think…


Hassan S. ------------------------ [email protected]

twitter: @hassan

On 11 August 2011 22:58, Leonel . [email protected] wrote:

validates :password,
:presence => true,
:length => { :minimum => 6, :maximum => 20},
:confirmation => true,
:on => :update

But everytime I try to change the user’s first name, I get the error
messages that the username is already taken and such. I’m not even
trying to update the username. And there is NOT EVEN A FIELD for the
username in the form.

Just to add to other posts, validations are nothing to do with data in
fields on the form, or even actions in controllers, they are run by
the model when a database record is created or updated by any method,
the validation has no knowledge of where the data in the record being
written came from.

Having said that I do not understand your comment above, you say you
get the problem when you try to change the username, but then say that
there is not a field for username in the form. However
validates_uniqueness_of should not be failing in the way you describe
on update, and if you want to ensure uniqueness then you should be
running the validation on update (and create). Perhaps some
controller code (just the action that is causing the problem) would be
interesting to see. Have you got any callback filters on the model
that might be confusing the issue?

On a separate note, if you wish a field to be unique then
validates_uniqueness_of is not sufficient under some conditions
(google will explain why I am sure) so you should also put a
constraint in the database.

Colin

Thanks to everybody for their comments, it’s helping me understand Rails
more :slight_smile:

I’m going to try your suggestions.

Colin L. wrote in post #1016307:
Having said that I do not understand your comment above, you say you
get the problem when you try to change the username, but then say that
there is not a field for username in the form.

Well, I’m trying to change the FIRST_NAME (and other fields but for
simplicity purposes let’s just say it’s only the first_name). I get
validation errors for the USERNAME and there’s NOT EVEN A FIELD FOR THE
USERNAME in the form.

On 12 August 2011 16:32, Leonel . [email protected] wrote:

Well, I’m trying to change the FIRST_NAME (and other fields but for
simplicity purposes let’s just say it’s only the first_name). I get
validation errors for the USERNAME and there’s NOT EVEN A FIELD FOR THE
USERNAME in the form.

As I said in my previous post VALIDATIONS ARE NOTHING TO DO WITH DATA
IN FIELDS ON THE FORM (yes, I can shout too), so it doesn’t make any
difference whether username is on the form or not, the validations are
still run on all fields that are being written. Perhaps you had
better read my previous mail again more carefully. Perhaps you were
shouting so loudly you could not hear what I was saying. There may be
other useful data in it that you missed.

If you are getting uniqueness errors when updating a record on a field
that you have not changed then that suggests that maybe you are trying
to create a new record rather than updating the existing one.

Colin

Colin

As I said in my previous post VALIDATIONS ARE NOTHING TO DO WITH DATA
IN FIELDS ON THE FORM (yes, I can shout too), so it doesn’t make any
difference whether username is on the form or not, the validations are
still run on all fields that are being written. Perhaps you had
better read my previous mail again more carefully. Perhaps you were
shouting so loudly you could not hear what I was saying. There may be
other useful data in it that you missed.

Somebody is sensitive todaaaay haha. Yes you’re right, that’s why I said
I’m going to try the suggestions, 'cause I haven’t yet. I was just
clarifying my post. geeeesh =P

I temporarily solved the username attribute by not letting the user
update the username. So the validation only works :on => :create
So username attribute validation problem solved.

Now I got the password validation problem. Ok, it seems the problem was
kinda of obvious but I couldn’t see it.

In user.rb I have this…

validates :password,
:presence => true,
:length => { :minimum => 6, :maximum => 20, :message => ‘should have
between 6 to 12 characters’ },
:confirmation => true

but the password attribute doesn’t even exist because it’s a virtual
attribute. The real attributes are password_hash and password_salt.

So the Change Password and Password Reset controllers and forms work
well.

When I go to the Edit User page, user can edit…

  • first name
  • last name
  • email
  • there is NO Password field

PROBLEM: So when the user tries to update his, let’s say, first name and
clicks on Save Changes, I get a password length and password can’t be
blank validation error.

I’m searching for something like “rails validation exception” to solve
this problem. If you have any suggestions please let me know.

Try this

:unless => Proc.new {|user| user.password.nil?}

Essentially it will check if you are sending a password attribute to the
user or not while updating the user record and will check for this
validation only if password attribute is present.

Chirag
http://sumeruonrails.com

Can someone help me complete this piece of code?

I’m thinking about using :unless because the only place where I wouldn’t
like the password validation is in the Edit User page.

validates :password,
:presence => true,
:length => { :minimum => 6, :maximum => 20, :message => ‘should have
between 6 to 12 characters’ },
:confirmation => true,
:unless => ???

I tried…
:unless => params[:controller] == ‘users’ and params[:action] == ‘edit’

but I got the following error…
Routing Error
undefined local variable or method `params’ for #Class:0x7f92ca83a518

Chirag S. wrote in post #1017423:

Try this

:unless => Proc.new {|user| user.password.nil?}

Essentially it will check if you are sending a password attribute to the
user or not while updating the user record and will check for this
validation only if password attribute is present.

Awesomeness!!! Last time I was working on it I was reading about Procs
but the documentation I found was kinda confusing to me. Thanks man! It
works now :smiley:

@7stud I can’t do that because I’m validation “password” which is an
attribute that doesn’t exist and when update_attributes is ran, it tries
to validate it.

Leonel . wrote in post #1017341:

I temporarily solved the username attribute by not letting the user
update the username. So the validation only works :on => :create
So username attribute validation problem solved.

Now I got the password validation problem. Ok, it seems the problem was
kinda of obvious but I couldn’t see it.

In user.rb I have this…

validates :password,
:presence => true,
:length => { :minimum => 6, :maximum => 20, :message => ‘should have
between 6 to 12 characters’ },
:confirmation => true

but the password attribute doesn’t even exist because it’s a virtual
attribute. The real attributes are password_hash and password_salt.

So the Change Password and Password Reset controllers and forms work
well.

When I go to the Edit User page, user can edit…

  • first name
  • last name
  • email
  • there is NO Password field

PROBLEM: So when the user tries to update his, let’s say, first name and
clicks on Save Changes, I get a password length and password can’t be
blank validation error.

Why aren’t you doing:

@user = User.find(params[:id])

if @user.update_attributes(params[:user])

===

Edit User

<%= form_for(@user) do |f| %>

<% render ‘shared/error_messages’, :object => f.object %>

<%= f.label :first_name %>
<%= f.text_field :first_name %>
<%= f.label :last_name %>
<%= f.text_field :last_name %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.submit "Update" %>

<% end %>

=======

def update
@user = User.find(params[:id])

if @user.update_attributes(params[:user])
flash[:success] = “Profile Updated”
redirect_to @user
else
@title = ‘Edit User’
render ‘edit’
end

end

===app/views/shared/_error_messages:

<% if object.errors.any? %>

<h2><%= pluralize(object.errors.count, 'error') %>
  prohibited your account from being created!</h2>

<p>There were problems with the following fields:</p>

<ul>
  <% object.errors.full_messages.each do |msg| %>
    <li><%= msg %></li>
  <% end %>
</ul>

<% end %>