Is there an easy way to make a Rails ActiveRecord model read-only?

后端 未结 8 1279
-上瘾入骨i
-上瘾入骨i 2021-01-31 01:25

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.

相关标签:
8条回答
  • 2021-01-31 01:50

    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
    
    0 讨论(0)
  • 2021-01-31 01:52

    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
    
    0 讨论(0)
  • 2021-01-31 01:59

    I've found a more concise solution, which uses the after_initialize callback:

    class Post < ActiveRecord::Base
      after_initialize :readonly!
    end
    
    0 讨论(0)
  • 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.

    0 讨论(0)
  • 2021-01-31 02:06

    TL;DR for OP's

    class YourModel < ActiveRecord::Base
      before_save { false } # prevent create & update, allows destroy
    
      # ... 
    end
    

    Generally

    • To prevent creates only: before_create { false }
    • To prevent updates only: before_update { false }
    • To prevent destroys only: before_destroy { false } # does not prevent delete

    See also: http://guides.rubyonrails.org/active_record_callbacks.html

    0 讨论(0)
  • 2021-01-31 02:08

    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
    
    0 讨论(0)
提交回复
热议问题