John Trichereau
John Trichereau

Reputation: 626

Rails 4 attr_readonly on update

I want to make an attribute read only for each record after the first update, is there a way to do this in Rails 4 using attr_readonly? Or another method?

It has to do with Transaction security...

Upvotes: 2

Views: 2636

Answers (1)

Jordan Running
Jordan Running

Reputation: 106077

attr_readonly is a class method, so it would "freeze" the attribute on all instances of the model, whether they've been updated or not.

The sanest way to do what you want, I think, would be to add a some_attribute_is_frozen boolean attribute to your model, and then set it to true in a before_update callback. Then you can have a validation that will only run if some_attribute_is_frozen? is true, and which will fail if the "frozen" attribute has changed.

Something like this (for the sake of an example I've arbitrarily chosen "Customer" as the name of the model and address as the name of the attribute you want to "freeze"):

# $ rails generate migration AddAddressIsFrozenToCustomers
# => db/migrate/2014XXXX_add_address_is_frozen_to_customers.rb
class AddAddressIsFrozenToCustomers < ActiveRecord::Migration
  def change
    add_column :customers, :address_is_frozen, :boolean,
      null: false, default: false
  end
end
# app/models/customer.rb
class Customer < ActiveRecord::Base
  before_update :mark_address_as_frozen  
  validate :frozen_address_cannot_be_changed, if: :address_is_frozen?

  # ...snip...

  private
  def mark_address_as_frozen
    self.address_is_frozen = true
  end

  def frozen_address_cannot_be_changed
    return unless address_changed?
    errors.add :address, "is frozen and cannot be changed"
  end
end

Since the before_update callback runs after validation, the very first time the record is updated, address_is_frozen? will return false and the validation will be skipped. On the next update, though, address_is_frozen? will return true and so the validation will run, and if address has changed the validation will fail with a useful error message.

I hope that's helpful!

Upvotes: 3

Related Questions