module ActiveRecord::QueryMethods

Public Instance Methods

build_arel(*args) click to toggle source
# File lib/activerecord-multi-tenant/query_rewriter.rb, line 256
def build_arel(*args)
  arel = build_arel_orig(*args)

  if !MultiTenant.with_write_only_mode_enabled?
    visitor = MultiTenant::ArelTenantVisitor.new(arel)

    visitor.contexts.each do |context|
      node = context.arel_node

      context.unhandled_relations.each do |relation|
        model = MultiTenant.multi_tenant_model_for_table(relation.arel_table.table_name)

        if MultiTenant.current_tenant_id
          enforcement_clause = MultiTenant::TenantEnforcementClause.new(relation.arel_table[model.partition_key])
          case node
          when Arel::Nodes::Join #Arel::Nodes::OuterJoin, Arel::Nodes::RightOuterJoin, Arel::Nodes::FullOuterJoin
            node.right.expr = node.right.expr.and(enforcement_clause)
          when Arel::Nodes::SelectCore
            if node.wheres.empty?
              node.wheres = [enforcement_clause]
            else
              node.wheres[0] = enforcement_clause.and(node.wheres[0])
            end
          else
            raise "UnknownContext"
          end
        end

        if node.is_a?(Arel::Nodes::SelectCore) || node.is_a?(Arel::Nodes::Join)
          if node.is_a?Arel::Nodes::Join
            node_list = [node]
          else
            node_list = node.source.right
          end

          node_list.select{ |n| n.is_a? Arel::Nodes::Join }.each do |node_join|
            if (!node_join.right ||
                (ActiveRecord::VERSION::MAJOR == 5 &&
                 !node_join.right.expr.right.is_a?(Arel::Attributes::Attribute)))
              next
            end

            relation_right, relation_left = relations_from_node_join(node_join)

            next unless relation_right && relation_left

            model_right = MultiTenant.multi_tenant_model_for_table(relation_left.table_name)
            model_left = MultiTenant.multi_tenant_model_for_table(relation_right.table_name)
            if model_right && model_left
              join_enforcement_clause = MultiTenant::TenantJoinEnforcementClause.new(relation_left[model_left.partition_key], relation_right)
              node_join.right.expr = node_join.right.expr.and(join_enforcement_clause)
            end
          end
        end
      end
    end
  end

  arel
end
Also aliased as: build_arel_orig
build_arel_orig(*args)
Alias for: build_arel

Private Instance Methods

relations_from_node_join(node_join) click to toggle source
# File lib/activerecord-multi-tenant/query_rewriter.rb, line 318
def relations_from_node_join(node_join)
  if ActiveRecord::VERSION::MAJOR == 5 || node_join.right.expr.is_a?(Arel::Nodes::Equality)
    return node_join.right.expr.right.relation, node_join.right.expr.left.relation
  end

  children = node_join.right.expr.children

  tenant_applied = children.any?(MultiTenant::TenantEnforcementClause) || children.any?(MultiTenant::TenantJoinEnforcementClause)
  if tenant_applied || children.empty?
    return nil, nil
  end

  if children[0].right.respond_to?('relation') && children[0].left.respond_to?('relation')
    return children[0].right.relation, children[0].left.relation
  end

  return nil, nil
end