class Recurso::Queries::Relation

Public Class Methods

new(identity, resource, relation_name, all_columns: true, action: :view, include_actions: []) click to toggle source
# File lib/recurso/queries/relation.rb, line 5
def initialize(identity, resource, relation_name, all_columns: true, action: :view, include_actions: [])
  @identity = identity
  @resource = resource
  @relation = resource.send(relation_name)
  @all_columns = all_columns
  @include_actions = (include_actions + Array(action)).uniq
  @action = action
end

Public Instance Methods

resources() click to toggle source
# File lib/recurso/queries/relation.rb, line 14
def resources
  @relation
    .select("#{@relation.table_name}.#{@all_columns ? :"*" : :id}")
    .select(*@include_actions.map { |action| "included.can_#{action}"})
    .joins("
      INNER JOIN (#{included_permissions}) included
      ON #{@relation.table_name}.id = included.id
      AND included.can_#{@action} = 1
    ")
end

Private Instance Methods

cascaded_permissions() click to toggle source
# File lib/recurso/queries/relation.rb, line 35
def cascaded_permissions
  @relation.relevant_associations.map do |assoc|
    @relation
      .select(:id, :level)
      .joins(through_join_for(assoc))
      .joins("
        INNER join #{permission_class.table_name}
        ON  #{permission_class.table_name}.resource_type = '#{assoc.class_name}'
        AND #{permission_class.table_name}.resource_id   = #{resource_id_for(assoc)}
        AND #{permission_class.table_name}.#{identity_foreign_key} = #{@identity.id.to_i}
      ").to_sql
  end.join(" UNION ")
end
identity_foreign_key() click to toggle source
# File lib/recurso/queries/relation.rb, line 73
def identity_foreign_key
  @identity_foreign_key ||= Recurso::Config.instance.identity_foreign_key_for(@identity.class)
end
included_permission_select() click to toggle source
# File lib/recurso/queries/relation.rb, line 49
def included_permission_select
  @include_actions.map do |action|
    level_values = @resource.relevant_levels_for(action).map { |level| permission_class.levels[level] }.join(',')

    "cascaded.level IN (#{level_values}) as can_#{action}"
  end.join(", ")
end
included_permissions() click to toggle source
# File lib/recurso/queries/relation.rb, line 27
def included_permissions
  "
    SELECT cascaded.id, #{included_permission_select}
    FROM (#{cascaded_permissions}) cascaded
    GROUP BY cascaded.id
  "
end
permission_class() click to toggle source
# File lib/recurso/queries/relation.rb, line 69
def permission_class
  @permission_class ||= Recurso::Config.instance.permission_class_name_for(@identity.class).constantize
end
resource_id_for(assoc) click to toggle source
# File lib/recurso/queries/relation.rb, line 57
def resource_id_for(assoc)
  "#{(assoc.through_reflection || assoc.active_record).table_name}.#{assoc.foreign_key}"
end
through_join_for(assoc) click to toggle source
# File lib/recurso/queries/relation.rb, line 61
def through_join_for(assoc)
  return unless through = assoc.through_reflection
  "
    LEFT OUTER JOIN #{through.table_name}
    ON #{through.table_name}.#{through.association_primary_key} = #{resource_id_for(through)}
  "
end