I want to be able to create a record in the DB but then prevent Rails from making changes from that point on. I understand changes will still be possible at the DB level.
Looking at ActiveRecord::Persistence, everything ends up calling create_or_update
behind the scenes.
def create_or_update
raise ReadOnlyRecord if readonly?
result = new_record? ? create : update
result != false
end
So! Just:
def readonly?
!new_record?
end
A custom validator can do this:
validate :nothing_changed, unless: :new_record? # make immutable
...
def nothing_changed
errors.add(:base, "Record is read-only") if self.changed?
end
I've found a more concise solution, which uses the after_initialize
callback:
class Post < ActiveRecord::Base
after_initialize :readonly!
end
This seems to be fairly effective and is probably a bit overkill, but for my case, I really want to be sure my application will never create, save, update, or destroy any records in the model, ever.
module ReadOnlyModel
def readonly?() true end
def create_or_update() raise ActiveRecord::ReadOnlyRecord end
before_create { raise ActiveRecord::ReadOnlyRecord }
before_destroy { raise ActiveRecord::ReadOnlyRecord }
before_save { raise ActiveRecord::ReadOnlyRecord }
before_update { raise ActiveRecord::ReadOnlyRecord }
end
class MyModel < ActiveRecord::Base
include ReadOnlyModel
# ...
end
Since OP asked to be able to create and destroy but not save or update I believe this will work
module SaveAndDestroyOnlyModel
before_save { raise ActiveRecord::ReadOnlyRecord }
before_update { raise ActiveRecord::ReadOnlyRecord }
end
class MyModel < ActiveRecord::Base
include SaveAndDestroyOnlyModel
# ...
end
Not exactly the right exception, but close enough I think.
class YourModel < ActiveRecord::Base
before_save { false } # prevent create & update, allows destroy
# ...
end
before_create { false }
before_update { false }
before_destroy { false } # does not prevent delete
See also: http://guides.rubyonrails.org/active_record_callbacks.html
Why not just create a user on the database that has read only access, and have rails use that account.
However if you want model level access, you can add the following to a specific model:
def readonly?
true
end
def before_destroy
raise ActiveRecord::ReadOnlyRecord
end