# Usage: # This module adds single scoped sequential id on AR model. # In your model, include this module like: # include SequentialId[:number, scope: :user_id] module SequentialId def self.[](column_name, scope:) options = Struct.new(:column_name, :scope) Module.new do extend ActiveSupport::Concern include SequentialId included do before_save :set_sequential_id end define_method(:sequential_id_options) { options.new(column_name, scope) } end end private def query_last_sequential_id_value column_name = sequential_id_options.column_name scope_column_name = sequential_id_options.scope scope_condition = { scope_column_name => self[scope_column_name] } base_relation = self.class.base_class.unscoped value = base_relation.where(scope_condition).where.not(column_name => nil) .lock .order(column_name => :desc).limit(1) .first&.send(column_name) value || 0 end def set_sequential_id column_name = sequential_id_options.column_name return if self[column_name] self[column_name] = query_last_sequential_id_value + 1 end end