Module: VirtualDelegates

Extended by:
ActiveSupport::Concern
Included in:
VirtualAttributes
Defined in:
lib/extensions/ar_virtual.rb

Defined Under Namespace

Modules: ClassMethods

Class Method Summary collapse

Class Method Details

.select_from_alias(to_ref, col, to_model_col_name, src_model_id) ⇒ Arel::Node

select_from_alias: helper method for virtual_delegate_arel to construct the sql see also virtual_delegate_arel

example

for the given belongs_to class definition:

  class Vm
    belongs_to :hosts #, :foreign_key => :host_id, :primary_key => :id
    virtual_delegate :name, :to => :host, :prefix => true, :allow_nil => true
  end

The virtual_delegate calls:

  virtual_delegate_arel("name", Vm.reflection_with_virtual(:host))

which calls:

  select_from_alias(Vm.reflection_with_virtual(:host), "name", "id", Vm.arel_table[:host_id])

which produces the sql:

  SELECT to_model[col] from to_model where to_model[to_model_col_name] = src_model_table[:src_model_id]
  (SELECT "hosts"."name" FROM "hosts" WHERE "hosts"."id" = "vms"."host_id")

----

for the given has_one class definition

  class Host
    has_one :hardware
    virtual_delegate :name, :to => :hardware, :prefix => true, :allow_nil => true
  end

The virtual_delegate calls:

  virtual_delegate_arel("name", Host.reflection_with_virtual(:hardware))

which at runtime will call select_from_alias:

  select_from_alias(Host.reflection_with_virtual(:hardware), "name", "host_id", Host.arel_table[:id])

which produces the sql (ala arel):

  #select to_model[col] from to_model where to_model[to_model_col_name] = src_model_table[:src_model_id]
  (SELECT "hardwares"."name" FROM "hardwares" WHERE "hardwares"."host_id" = "hosts"."id")

----

for the given self join class definition:

  class Vm
    belongs_to :src_template, :class => Vm
    virtual_delegate :name, :to => :src_template, :prefix => true, :allow_nil => true
  end

The virtual_delegate calls:

  virtual_delegate_arel("name", Vm.reflection_with_virtual(:src_template))

which calls:

  select_from_alias(Vm.reflection_with_virtual(:src_template), "name", "src_template_id", Vm.arel_table[:id])

which produces the sql:

  #select to_model[col] from to_model where to_model[to_model_col_name] = src_model_table[:src_model_id]
  (SELECT "vms_sub"."name" FROM "vms" AS "vms_ss" WHERE "vms_ss"."id" = "vms"."src_template_id")

289
290
291
292
293
294
# File 'lib/extensions/ar_virtual.rb', line 289

def self.select_from_alias(to_ref, col, to_model_col_name, src_model_id)
  to_table = select_from_alias_table(to_ref.klass, src_model_id.relation)
  to_model_id = to_ref.klass.arel_attribute(to_model_col_name, to_table)
  to_column = to_ref.klass.arel_attribute(col, to_table)
  Arel.sql("(#{to_table.project(to_column).where(to_model_id.eq(src_model_id)).to_sql})")
end

.select_from_alias_table(to_klass, src_relation) ⇒ Object

determine table reference to use for a sub query

typically to_table is just the table used for the to_ref but if it is a self join, then it will also have an alias


300
301
302
303
304
305
306
307
308
309
310
# File 'lib/extensions/ar_virtual.rb', line 300

def self.select_from_alias_table(to_klass, src_relation)
  to_table = to_klass.arel_table  # if a self join, alias the second table to a different name

  if to_table.table_name == src_relation.table_name    # use a dup to not modify the primary table in the model

    to_table = to_table.dup    # use a table alias to not conflict with table name in the primary query

    to_table.table_alias = "#{to_table.table_name}_sub"
  end
  to_table
end