Module: ActiveRecord::VirtualAttributes::VirtualDelegates

Extended by:
ActiveSupport::Concern
Included in:
ActiveRecord::VirtualAttributes
Defined in:
lib/active_record/virtual_attributes/virtual_delegates.rb

Overview

VirtualDelegate is the same as delegate, but adds sql support, and a default when a value is not found

Model.belongs_to :association Model.virtual_delegate :field1, :field2, to: :association

Model.select(:field1) # now works

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| ... } ⇒ Object

Based upon ActiveRecord AssociationScope.scope

Yields:

  • (arel)


239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
# File 'lib/active_record/virtual_attributes/virtual_delegates.rb', line 239

def self.select_from_alias(to_ref, col, to_model_col_name, src_model_id)
  query = if to_ref.scope
            to_ref.klass.instance_exec(nil, &to_ref.scope)
          else
            to_ref.klass.all
          end

  src_model = to_ref.active_record
  to_table  = select_from_alias_table(to_ref.klass, src_model_id.relation)
  to_model_id = to_ref.klass.arel_table[to_model_col_name, to_table]
  to_column   = to_ref.klass.arel_table[col, to_table]
  arel = query.except(:select).select(to_column).arel
              .from(to_table)
              .where(to_model_id.eq(src_model_id))

  # :type is in the reflection definition (meaning it is polymorphic)
  if to_ref.type
    # get the class name (e.g. "Host")
    polymorphic_type = src_model.base_class.name
    arel = arel.where(to_ref.klass.arel_table[to_ref.type].eq(polymorphic_type))
  end

  yield arel if block_given?

  # convert arel to sql to populate with bind variables
  ::Arel::Nodes::Grouping.new(Arel.sql(arel.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



271
272
273
274
275
276
277
278
279
280
281
# File 'lib/active_record/virtual_attributes/virtual_delegates.rb', line 271

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