What is provided in ActiveRecord only affects some behaviors I'm worried about leaks, but I'll have to do my best to make a module to seal it.
Place it around lib / autoload / active_record_read_only.rb
module ActiveRecordReadOnly
extend ActiveSupport::Concern
# ActiveRecord::Should be rolled back with a ReadOnlyRecord error
#It's not necessary to move it in vain, so seal it
included do
before_save { self.class.raise_readonly! }
before_create { self.class.raise_readonly! }
before_update { self.class.raise_readonly! }
before_destroy { self.class.raise_readonly! }
end
#Basic ReadOnly control
def readonly?
true
end
#Seal touch
#This is not enough for the following reasons, but it is overwritten to match the judgment function with the actual behavior.
def no_touching?
true
end
#Seal touch
# no_touching?If you just seal it with, it will not cause an error, so seal it directly
def touch
self.class.raise_readonly!
end
module ClassMethods
# update_column and update_columns etc readonly?Block column specification processing without judgment
def readonly_attributes
attribute_names
end
# readonly?Since it is a single process without judgment, it is sealed directly
def delete(_id)
raise_readonly!
end
#Since it is a batch operation and no column is specified, it is sealed directly.
def delete_all
raise_readonly!
end
#Since it is a batch operation and no column is specified, it is sealed directly.
def update_all(_attributes)
raise_readonly!
end
def raise_readonly!
raise ActiveRecord::ReadOnlyRecord,
"#{name}.included ActiveRecordReadOnly"
end
end
end
Just include
class User < ApplicationRecord
include ActiveRecordReadOnly
end
It's closed
[1] pry(main)> ActiveRecord::Base.logger = nil
=> nil
[2] pry(main)> User.first.destroy
ActiveRecord::ReadOnlyRecord: User.included ActiveRecordReadOnly
from /app/lib/autoload/active_record_read_only.rb:52:in `raise_readonly!'
[3] pry(main)> User.first.update(code: 'test')
ActiveRecord::ReadOnlyRecord: User.included ActiveRecordReadOnly
from /app/lib/autoload/active_record_read_only.rb:52:in `raise_readonly!'
[4] pry(main)> User.first.update_columns(code: 'test')
ActiveRecord::ActiveRecordError: code is marked as readonly
from /usr/local/bundle/gems/activerecord-6.0.0/lib/active_record/persistence.rb:947:in `verify_readonly_attribute'
[5] pry(main)> User.first.update_column(:code, 'test')
ActiveRecord::ActiveRecordError: code is marked as readonly
from /usr/local/bundle/gems/activerecord-6.0.0/lib/active_record/persistence.rb:947:in `verify_readonly_attribute'
[6] pry(main)> User.first.touch
ActiveRecord::ReadOnlyRecord: User.included ActiveRecordReadOnly
from /app/lib/autoload/active_record_read_only.rb:52:in `raise_readonly!'
[7] pry(main)> User.create(code: 'test')
ActiveRecord::ReadOnlyRecord: User.included ActiveRecordReadOnly
from /app/lib/autoload/active_record_read_only.rb:52:in `raise_readonly!'
[8] pry(main)> User.delete(1)
ActiveRecord::ReadOnlyRecord: User.included ActiveRecordReadOnly
from /app/lib/autoload/active_record_read_only.rb:52:in `raise_readonly!'
[9] pry(main)> User.delete_all
ActiveRecord::ReadOnlyRecord: User.included ActiveRecordReadOnly
from /app/lib/autoload/active_record_read_only.rb:52:in `raise_readonly!'
[10] pry(main)> User.update_all(code: 'test')
ActiveRecord::ReadOnlyRecord: User.included ActiveRecordReadOnly
from /app/lib/autoload/active_record_read_only.rb:52:in `raise_readonly!'
When applied to the model body, it was meaningless because it can be defined after the blockade It is assumed that it will be separated into the inheritance model for viewing as shown below.
class User < ApplicationRecord
before_create -> { }
end
class ReadOnlyUser < User
include ActiveRecordReadOnly
end
Recommended Posts