Reputation:
I would like to know if it's possible to configure my model so it after created it becomes readonly. I've tried to use the readonly?
method:
class Post < ApplicationRecord
belongs_to :blog
def readonly?
true
end
end
But this also prevents creation, which doesn't make any sense IMO.
Upvotes: 0
Views: 79
Reputation: 102222
class Post < ApplicationRecord
def readonly?
persisted?
end
end
irb(main):001:0> p = Post.create(name: 'Hello World')
(0.3ms) BEGIN
Post Create (1.6ms) INSERT INTO "posts" ("name", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["name", "Hello World"], ["created_at", "2019-12-10 23:17:04.300537"], ["updated_at", "2019-12-10 23:17:04.300537"]]
(0.5ms) COMMIT
=> #<Post id: 1, name: "Hello World", created_at: "2019-12-10 23:17:04", updated_at: "2019-12-10 23:17:04">
irb(main):002:0> p.update(name: p.name.reverse)
Traceback (most recent call last):
1: from (irb):2
ActiveRecord::ReadOnlyRecord (Post is marked as readonly)
Although Fran Martinez's answers makes sense if you want to use a validation to create a user friendly response instead of rescuing ActiveRecord::ReadOnlyRecord
. It really boils down to the use case - is updating the record an exceptional event that should not be able to occur or is it something that could happen due to user error?
Upvotes: 1
Reputation: 3052
There are several ways to do so, but if you want something reusable in other models, you could try the next:
class ReadonlyValidator < ActiveModel::Validator
def validate(record)
return unless record.persisted?
record.errors[:base] << "#{record.class.name} is readonly."
end
end
class Post < ApplicationRecord
validates_with ReadonlyValidator
end
That way, you can do:
p = Post.create(body: "hello world")
> true
p.update(body: "bye bye")
> false
p.errors.message
> {:base=>["Post is readonly."]}
Upvotes: 1