ActiveRecord update_attribute vs update_attributes

Greetings all,

I would like to start a conversation about the subtle difference between update_attribute and update_attributes, namely that update_attribute skips validations and update_attributes does not skip validations.

I know this has been around for a while but is Rails 4 the time to make them both respect validations? I am willing to do the work if the core team feels like it would be a worthwhile breaking change.

I don’t have a ton of context on the history but as I talk to more and more beginners (and advanced) Rails folks, that subtle difference does trip people up.

Thanks,

Mike

+1 for making update_attribute run validations.

There is some bit of history here.

The purpose of update_attribute was to be able to touch an attribute fast, set a flag for example… something you know can go straight to the database. Indeed, update_attribute has never run validations.

There was some discussion about this method for Rails 3 because if the goal was to bypass stuff to be fast it didn’t felt consistent to still go through the callbacks. And for some time update_attribute skipped also callbacks in edge:

https://github.com/rails/rails/commit/01629d180468049d17a8be6900e27a4f0d2b18c4

though it still touched updated_at, so fast but not quite there.

That method is so popular, however, that the change felt too risky because it was subtle, and that was reverted just before shipping:

https://github.com/rails/rails/commit/30ea923040ded944209c98383389b6c9aafe806a

In the end, in 3.1 it was decided to introduce instead a new method update_column. That is the fast one.

Given the current status of things, I personally agree that running validations in update_attribute in Rails 4 would be a good idea.

Let’s see what other core team members think though. Thoughts?

Perhaps off topic – I’ve got an unreleased gem that patches save() and create() in ActiveRecord so that you can skip callbacks (and validations, although I know you can already do that). You’d do something like obj.save(:skip_callbacks => true, :skip_validations => true).

Is there a reason this behaviour is absent from ActiveRecord? Would people welcome it if I submitted a pull request with this feature?

I don't think that the 's' is a big enough change to make it noticeable. I like update_column, maybe a bang method would make sense too. But I'd expect them to both run validations.

Maybe deprecating one is a good idea.

Thanks for the history lesson Xavier.

Knowing that history, I like Steve’s idea of deprecating update_attribute and advertising update_column as the fast way to update a single column and update_attributes as the way to run through the whole update “stack”.

FWIW: This subtle difference disturbed me so much that I just alias update_attribute to update_attributes.

I’m very pleased to learn about update_column for the strange edge case where you need it direct.

+1 for deprecation and emphasizing update_column.

I personally find confusing the difference between update_attributes and update_attribute. Intuitively, it seems that it is only a matter of plural/singular (the first one changes more than one attribute through a Hash argument and the second one changes only one through a column and a value argument). Therefore, the implicitly validation skipping is something that I (and when I say I, I’m saying IMHO) dislike.

I’m +1 for the change :).

Cool, so after this thread and some discussion we have decided to deprecate update_attribute in 3-2-stable and remove it in Rails 4. Nowadays it has little sense, and the singular/plural distinction does not seem to deserve a dedicated method that does the same (if we added validations to update_attribute).

Would anyone be so kind as to volunteer a pull request for this?

I'll give it a go right now.

Steve,

It’d be cool if the patch included the addition of a :validate => false option in update_attributes.

This would make for an easier upgrade path from update_attribute.

Brian

I think that would be a different discussion with a different patch. Let this one be focused on the deprecation + removal.

I think the use case “only skip validations” is rare, and historically people used update_attribute as the closest we have to update_column. I believe the deprecation message should point to update_column, with minor emphasis buy mentioning also update_attributes.

Xavier

I think I can give you a hand adding the deprecation.

Thanks Rodrigo, Steve already volunteered though :).

Note that there's one additional difference, due to attribute whitelisting. Thus:

some_object.update_attribute(:foo, 'bar')

is NOT the same as:

some_object.update_attributes(foo: 'bar')

if foo isn't mass-assignable.

Not sure if it's terribly relevant, but worth mentioning.

--Matt Jones

This has now been merged, in both master and 3.2. Good job everyone!

Hello,

I know this change made it into 4.0, with a deprecation in 3.2 and was later reverted (I believe) so as not to deprecate functionality in a patch release.

I think the intent was for update_attribute to still be deprecated in 4.0. Is this right?

If so, I’ve submitted a pull request to do this deprecation:

https://github.com/rails/rails/pull/9383

Is it indeed intended to be deprecated?

Thanks,

Andrew.