Вот мое решение аналогичной проблемы: у нас есть поля, которые мы хотим, чтобы пользователь мог устанавливать самостоятельно, мы не требуем их при создании записи, но мы НЕ хотим, чтобы они были изменены после того, как они установлены.
validate :forbid_changing_some_field, on: :update
def forbid_changing_some_field
return unless some_field_changed?
return if some_field_was.nil?
self.some_field = some_field_was
errors.add(:some_field, 'can not be changed!')
end
Что меня удивило, так это то, что update_attribute
все еще работает, оно обходит проверки. Не такая уж большая проблема, поскольку на практике массово обновляются записи, но я это высказал в тестах, чтобы прояснить это. Вот несколько тестов для этого.
describe 'forbids changing some field once set' do
let(:initial_some_field) { 'initial some field value' }
it 'defaults as nil' do
expect(record.some_field).to be nil
end
it 'can be set' do
expect {
record.update_attribute(:some_field, initial_some_field)
}.to change {
record.some_field
}.from(nil).to(initial_some_field)
end
describe 'once it is set' do
before do
record.update_attribute(:some_field, initial_some_field)
end
it 'makes the record invalid if changed' do
record.some_field = 'new value'
expect(record).not_to be_valid
end
it 'does not change in mass update' do
expect {
record.update_attributes(some_field: 'new value')
}.not_to change {
record.some_field
}.from(initial_some_field)
end
it 'DOES change in update_attribute!! (skips validations' do
expect {
record.update_attribute(:some_field, 'other new value')
}.to change {
record.some_field
}.from(initial_some_field).to('other new value')
end
end
end