module IAmICan::Dynamic

Public Instance Methods

assignment_helpers() click to toggle source
# File lib/i_am_i_can/helpers/dynamic.rb, line 61
def assignment_helpers
  #
  # Generate methods for each Content of Assignment
  #
  # Example for a subject model called User, which `has_and_belongs_to_many :stored_roles`.
  # You call the proc below by given contents [:role], then:
  #
  proc { |contents| contents.each do |content|
    content_cls = i_am_i_can.send("#{content}_class") rescue next
    _plural = '_' + content.to_s.pluralize
    __plural = send("_#{_plural}")

    # _stored_roles_exec
    #   Add / Remove (by passing action :cancel) roles to a user instance
    define_method "_#{_reflect_of(content)}_exec" do |action = :assign, instances = [ ], **conditions|
      collection, objects = send(_plural), [ ]
      records = conditions.present? ? content_cls.constantize.where(conditions) : [ ]

      case action
      when :assign  then collection << objects = (records + instances).uniq - collection
      when :cancel  then collection.destroy objects = (records + instances).uniq & collection
      when :replace then send("#{__plural}=", objects = (records + instances).uniq) # collection=
      end
      objects
    end
    #
    alias_method "_stored#{_plural}_exec", "_#{_reflect_of(content)}_exec"
  end }
end
class_reflections() click to toggle source
# File lib/i_am_i_can/helpers/dynamic.rb, line 31
def class_reflections
  #
  # Extend each associated querying to a class method that returns ActiveRecord::Relation
  #
  # Suppose: in UserRole model,
  #   has_and_belongs_to_many :related_users
  #
  # It will do like this:
  #   def self.related_users
  #     User.with_stored_roles.where(user_roles: { id: self.ids })
  #   end
  #
  # Usage:
  #   UserRole.all.related_users
  #
  proc do
    %w[ subject role role_group permission ].each do |k|
      next if _reflect_of(k).blank?
      define_singleton_method _reflect_of(k) do
        model = i_am_i_can.send("#{k}_model")
        raise NoMethodError unless (reflect_name = model._reflect_of(i_am_i_can.act))

        model.send("with_#{reflect_name}").where(
            self.name.underscore.pluralize => { id: self.ids }
        )
      end
    end
  end
end
definition_helpers() click to toggle source
# File lib/i_am_i_can/helpers/dynamic.rb, line 91
def definition_helpers
  #
  # Generate class methods for each Content of Definition
  #
  # Example for a subject model called User,
  #   which `has_many_temporary_roles` and `has_and_belongs_to_many :stored_roles`.
  # You call the proc below by given contents [:role], then:
  #
  proc { |contents| contents.each do |content|
    content_cls = i_am_i_can.send("#{content}_class") rescue next
    _plural = '_' + content.to_s.pluralize

    # _create_roles
    #    Define and store roles of Subject
    define_singleton_method "_create#{_plural}" do |objects|
      # Role.create([{ name: .. }]).reject { the roles that validation failed }
      content_cls.constantize.create(objects)
          .reject {|record| record.new_record? }
    end
  end }
end
scopes() click to toggle source
# File lib/i_am_i_can/helpers/dynamic.rb, line 7
def scopes
  #
  # Generate scopes of each specified i_am_i_can association
  #
  # scope :with_stored_roles, -> { includes(:stored_roles) }
  #
  # Usage:
  #   User.with_stored_roles(role_id = 1)
  #   User.with_stored_roles?(role_id = 1)
  proc do |keys|
    keys.each do |k|
      scope :"with_#{_reflect_of(k)}", -> (ids = nil) do
        break includes(_reflect_of(k)) unless ids
        includes(_reflect_of(k)).where(
            i_am_i_can.send("#{k}_class").underscore.pluralize => { id: ids })
      end

      define_singleton_method :"with_#{_reflect_of(k)}?" do |ids|
        send(:"with_#{_reflect_of(k)}", ids).present?
      end
    end
  end
end