update_attributes() for a single column

44 views
Skip to first unread message

rihad

unread,
May 19, 2013, 4:03:51 AM5/19/13
to Ruby on Rails: Talk
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: "f...@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:
'exa...@railstutorial.org')
(2.1ms) BEGIN
User Exists (4.2ms) SELECT 1 AS one FROM "users" WHERE
(LOWER("users"."email") = LOWER('exa...@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
-----------------+-----------------------------
+----------------------------------------------------
id | integer | not null default
nextval('users_id_seq'::regclass)
name | character varying(255) |
email | character varying(255) |
created_at | timestamp without time zone |
updated_at | timestamp without time zone |
password_digest | character varying(255) |
Indexes:
"users_pkey" PRIMARY KEY, btree (id)
"index_users_on_email" UNIQUE, btree (email)


The strange thing is that listing most of the fields in the update
works (as instructed in the tutorial http://ruby.railstutorial.org/chapters/sign-up?version=4.0#top
in the section of adding Gravatar).

irb(main):007:0> user.update_attributes(name: 'Example User', email:
'exa...@railstutorial.org', password: 'foobar',
password_confirmation: 'foobar')
(3.0ms) BEGIN
User Exists (0.9ms) SELECT 1 AS one FROM "users" WHERE
(LOWER("users"."email") = LOWER('exa...@railstutorial.org') AND
"users"."id" != 1) LIMIT 1
SQL (133.5ms) UPDATE "users" SET "name" = $1, "email" = $2,
"password_digest" = $3, "updated_at" = $4 WHERE "users"."id" = 1
[["name", "Example User"], ["email", "exa...@railstutorial.org"],
["password_digest", "$2a
$10$0i9ihaDD9nU6QxiGNiKEGeIarY9faPWY9lAAlLIzYz8UMyyz7R/mW"],
["updated_at", Sun, 19 May 2013 07:55:25 UTC +00:00]]
(0.6ms) COMMIT


how come? What connection do other fields bear with the ability to
save the model?

Here's the model:
class User < ActiveRecord::Base
before_save { email.downcase! }
validates :name, presence: true, length: { maximum: 50 }
validates :email, presence: true,
format: { with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/
i },
uniqueness: { case_sensitive: false }
has_secure_password
validates :password_confirmation, presence: true
validates :password, length: { minimum: 6 }
end


Rails 4.0.0.beta1, Ruby ruby-2.0.0.0, ruby20-gems-1.8.25

rihad

unread,
May 19, 2013, 4:14:47 AM5/19/13
to Ruby on Rails: Talk
> 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.

Frederick Cheung

unread,
May 19, 2013, 4:37:50 AM5/19/13
to rubyonra...@googlegroups.com
On Sunday, May 19, 2013 9:14:47 AM UTC+1, rihad wrote:
>
>
> 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

Javix

unread,
May 19, 2013, 4:51:39 AM5/19/13
to rubyonra...@googlegroups.com
Did you define:

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

rihad

unread,
May 19, 2013, 5:14:04 AM5/19/13
to Ruby on Rails: Talk


On May 19, 1:37 pm, Frederick Cheung <frederick.che...@gmail.com>
wrote:
> 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.
>

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: "exa...@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.

rihad

unread,
May 19, 2013, 5:18:13 AM5/19/13
to Ruby on Rails: Talk
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).
Reply all
Reply to author
Forward
0 new messages