class Noid::Rails::Minter::Db

A minter backed by a database table. You would select this if you need to mint identifers on several distributed front-ends that do not share a common file system.

Public Instance Methods

read() click to toggle source
# File lib/noid/rails/minter/db.rb, line 12
def read
  deserialize(instance)
end
write!(minter) click to toggle source
# File lib/noid/rails/minter/db.rb, line 16
def write!(minter)
  serialize(instance, minter)
end

Protected Instance Methods

deserialize(inst) click to toggle source

@param [MinterState] inst minter state to be converted @return [Hash{Symbol => String, Object}] minter state as a Hash, like read @see read, Noid::Rails::Minter::Base#read

# File lib/noid/rails/minter/db.rb, line 25
def deserialize(inst)
  filtered_hash = inst.as_json.slice('template', 'counters', 'seq', 'rand', 'namespace')
  if filtered_hash['counters']
    filtered_hash['counters'] = JSON.parse(filtered_hash['counters'],
                                           symbolize_names: true)
  end
  filtered_hash.symbolize_keys
end
instance() click to toggle source

@return [MinterState]

# File lib/noid/rails/minter/db.rb, line 68
def instance
  MinterState.lock.find_by!(
    namespace: Noid::Rails.config.namespace,
    template: Noid::Rails.config.template
  )
rescue ActiveRecord::RecordNotFound
  MinterState.seed!(
    namespace: Noid::Rails.config.namespace,
    template: Noid::Rails.config.template
  )
end
next_id() click to toggle source

Uses pessimistic lock to ensure the record fetched is the same one updated. Should be fast enough to avoid terrible deadlock. Must lock because of multi-connection context! (transaction is per connection – not enough) The DB table will only ever have at most one row per namespace. The 'default' namespace row is inserted by `rails generate noid:rails:seed` or autofilled by instance below. If you want another namespace, edit your config initialzer to something like:

Noid::Rails.config.namespace = 'druid'
Noid::Rails.config.template = '.reeedek'

and in your app run:

bundle exec rails generate noid:rails:seed
# File lib/noid/rails/minter/db.rb, line 56
def next_id
  id = nil
  MinterState.transaction do
    locked = instance
    minter = ::Noid::Minter.new(deserialize(locked))
    id = minter.mint
    serialize(locked, minter)
  end
  id
end
serialize(inst, minter) click to toggle source

@param [MinterState] inst a locked row/object to be updated @param [::Noid::Minter] minter state containing the updates

# File lib/noid/rails/minter/db.rb, line 36
def serialize(inst, minter)
  # namespace and template are the same, now update the other attributes
  inst.update!(
    seq: minter.seq,
    counters: JSON.generate(minter.counters),
    rand: Marshal.dump(minter.instance_variable_get(:@rand))
  )
end