user12212177
user12212177

Reputation:

How to configure my model to be readonly after first time being created

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

Answers (2)

max
max

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

Fran Martinez
Fran Martinez

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

Related Questions