Make mongoid session read only

2019-07-07 07:03发布

I have different sessions in my mongoid.yml, where one session provides data from a static mongo database. I was wondering if it is possible, to "load" a session in read only mode, so that no changes with save, create, destroy or destroy_all can be made. My mongoid.yml looks like this:

production:
  sessions:
    default:
      database: my_app_production
      hosts:
        - localhost:27017
      options:
        read: primary
    static_content:
      database: static_content_db
      hosts:
        - localhost:27017
      options:
        read: primary
  options:
    use_utc: true

I have special models for the static_content session, they look like this:

  class StaticMappings
    include Mongoid::Document
    include Mongoid::Attributes::Dynamic
    store_in collection: "static_mappings", session: "static_content"
  end

I want to prevent myself form accidentially calling things like StaticMappings.destroy_all or a StaticMappings.create(...). Is this possible?

I found this Making an entire model read-only with Mongoid, but this won't prevent someone from calling create or destroy on a model instance.

1条回答
你好瞎i
2楼-- · 2019-07-07 07:22

That's an old question, but I met the same problem recently, so decided to share. Although, I want to notice, that this is not a per-sesson solution, but a per-model one.

As I figured out, there are two ways to make it possible:

1. Redefine readonly?

If you look through the Mongoid code, you'll see that all functions that save, delete or update, call readonly? to check if the model is read-only. Not really documented and has a drawback -- create and create! are allowed on this model (destroys, updates, saves won't run though).

private

def readonly?
  true
end

2. A custom callback

In addition to the previous method you can add callback(s) to ensure that even creates won't pass through:

before_create :readonly_secret

private

def readonly?
  true
end

def readonly_secret
  raise Mongoid::Errors::ReadonlyDocument, self.class if readonly?
end

Essentialy, you can get rid of readonly? method alltogether, and add other callbacks such as before_save, before_destroy, before_update, before_create

Manipulate "readonliness"

if you feel a need to manipulate read-only state from a runtime code, you can define an attribute for your model's class:

before_create :readonly_secret

class << self
  attr_accessor :readonly
end

private

def readonly?
  self.class.readonly.nil? ? true : self.class.readonly
end

def readonly_secret
  raise Mongoid::Errors::ReadonlyDocument, self.class if readonly?
  true
end
查看更多
登录 后发表回答