Skip to content

Instantly share code, notes, and snippets.

@stephancom
Created April 20, 2019 13:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stephancom/aff150a2511b368d2d7844fa1a63d5d6 to your computer and use it in GitHub Desktop.
Save stephancom/aff150a2511b368d2d7844fa1a63d5d6 to your computer and use it in GitHub Desktop.
not rewritable validator
en:
errors:
messages:
changed: "can't be changed"
class NotRewritableValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
return unless record.changed.include? attribute.to_s
return if record.changes[attribute.to_s].first.blank?
record.restore_attributes([attribute])
record.errors.add(attribute, options[:message] || I18n.t('errors.messages.changed'))
end
end
describe NotRewritableValidator do
subject do
Class.new do
include ActiveModel::Validations
include ActiveModel::Dirty
validates :write_once, not_rewritable: true
define_attribute_methods :write_once
def initialize
@write_once = nil
end
attr_reader :write_once
def write_once=(val)
write_once_will_change! unless val == @write_once
@write_once = val
end
def save
# do persistence work
changes_applied
end
def reload!
# get the values from the persistence layer
clear_changes_information
end
def rollback!
restore_attributes
end
end.new
end
describe 'nil field' do
it { expect(subject.write_once).to be nil }
it 'can be changed' do
subject.write_once = 'something'
subject.validate
expect(subject.errors[:write_once]).not_to include "can't be changed"
end
it 'does not revert the change' do
expect {
subject.write_once = 'something'
subject.validate
subject.save
}.to change {
subject.write_once
}.from(nil).to('something')
end
end
describe 'blank field' do
before do
subject.write_once = ''
subject.validate
subject.save
end
it { expect(subject.write_once).to eq('') }
it 'can be changed' do
subject.write_once = 'something'
subject.validate
expect(subject.errors[:write_once]).not_to include "can't be changed"
end
it 'does not revert the change' do
expect {
subject.write_once = 'something'
subject.validate
subject.save
}.to change {
subject.write_once
}.from('').to('something')
end
end
describe 'once field has been set' do
before do
subject.write_once = 'a thing'
subject.validate
subject.save
end
it 'makes the record invalid if changed' do
subject.write_once = 'another thing'
subject.validate
expect(subject.errors[:write_once]).to include "can't be changed"
end
it 'reverts the change' do
expect {
subject.write_once = 'another thing'
subject.validate
subject.save
}.not_to change {
subject.write_once
}.from('a thing')
end
end
end
@stephancom
Copy link
Author

I realize rolling back the change is a side effect and some might say it's a bad idea. I like it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment