update_attributes() for a single column

I was just faced with a strange ROLLBACK exception when attempting to execute this code:

$ rails console user = User.first   User Load (1.1ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 1 => #<User id: 1, name: "Michael Hartl", email: "foo@bar.com", created_at: "2013-05-12 12:47:23", updated_at: "2013-05-12 13:24:26", password_digest: "$2a $10$CYZFddDa5Glv0dlYhlpZguIuzfyMRiwleaenmh67hFyK..."> irb(main):005:0> user.update_attributes(email: 'example@railstutorial.org')    (2.1ms) BEGIN   User Exists (4.2ms) SELECT 1 AS one FROM "users" WHERE (LOWER("users"."email") = LOWER('example@railstutorial.org') AND "users"."id" != 1) LIMIT 1    (0.7ms) ROLLBACK => false

There definitely is no user in the database (Postgres) matching given email. blog=> \d users                                         Table "public.users"      Column | Type | Modifiers

class User < ActiveRecord::Base before_save { email.downcase! }

...

    validates :password\_confirmation, presence: true
    validates :password, length: \{ minimum: 6 \}

I now think it may be the peculiarity of the model: it validates presence of password confirmation, which makes no sense when password itself isn't or shouldn't be updated.

That is indeed weird - the only validation I've ever used in conjunction with the confirmation field is validates_confirmation_of. You can check user.errors to see all the errors rails thinks the object has.

Fred

Did you define:

attr_accessible :email, :name, :password, :password_confirmation, … #other attributes if needed

Thanks, it was indeed missing password + confirmation causing the ROLLBACK.

irb(main):004:0> user.errors => #<ActiveModel::Errors:0x29fe1b30 @base=#<User id: 1, name: "Example User", email: "exampl@railstutorial.org", created_at: "2013-05-12 12:47:23", updated_at: "2013-05-19 07:55:25", password_digest: "$2a $10$0i9ihaDD9nU6QxiGNiKEGeIarY9faPWY9lAAlLIzYz8U...">, @messages={:password_confirmation=>["can't be blank"], :password=>["is too short (minimum is 6 characters)"]}>

has_secure_password must be something new in Rails 4. It does everything validates_confirmation_of does. And attr_accessible also seems to have become a thing from the past.

Validation should be conditional. Considering that both password and password_confirmation are virtual and are never saved to the database (only password_digest, a special field expected by has_secure_password), their validation should be special cased (like only password being present to signify desire to change it, thus trigger the confirmation check).