Raise when an update to a read-only attribute is attempted

Currently, updates to read-only attributes fail silently. For example:

class ReadOnly < ActiveRecord::Base
  attr_readonly :name
end

record = ReadOnly.create(name: "original")
record.update(name: "changed") # true
record.reload.name # "original"

``

This behavior is highly unexpected to me because it provides no feedback that the updates were not persisted, a significant exception to the normal behavior of #update and #save.

Raising an error whenever an update is attempted, or treating attr_readonly as a validation both seem like good options to me. I’ve attempted to implement the former (mostly because it was simpler) here: https://github.com/CJStadler/rails/commit/3fe8a29429a3dade8877513db653851b7a43333d.

I realize this would be a breaking change and can’t be undertaken lightly, but the current behavior feels like a big “gotcha”, and one that’s difficult to debug.

Thanks!

Chris Stadler

1 Like

I would also like to see a noisy failure on attempted update, or the option of one.

A good approach would be to add an option to the attr_readonly call to support raise on attempted update. The default behavior could be switched in a later release if desired.

1 Like

It works exactly as documented:

“will be used to create a new record but update operations will ignore these fields.”

If that isn’t the behavior you want, you’re probably better off using a different solution, rather than changing the intended behavior for everyone. Maybe override the attribute setter:

def name=(val)

raise ActiveRecord::ReadOnlyRecord.new("Name is readonly) if persisted?

super

end

I agree that it works as documented. I’m not saying that there is bug to fix, I’m proposing that the API could be improved.

I have not been able to find out what the motivation was for the current behavior (I think this is the initial commit), so I’m interested to know. It seems to me that any attempt to update a readonly attribute is probably the result of a bug. For example, a form may be exposing a readonly attribute (and then incorrectly reporting that the attribute was updated). I’m sure there are cases I haven’t thought of though. When is it necessary to allow attempted updates to readonly attributes?

I realize that we cannot just change the current behavior. Does Ben’s suggestion of adding an option on attr_readonly seem reasonable?

Thanks!

1 Like

This behavior was changed a few months ago in this pull request: Raise on assignment to readonly attributes

If you try to update a readonly attribute on a model that’s already saved in the database, Rails will raise ActiveRecord::ReadonlyAttributeError.

Set the config.active_record.raise_on_assign_to_attr_readonly setting to false to prevent Rails from raising this error.