# File lib/pragma/decorator/association/adapter/active_record.rb, line 66 def primary_key return associated_object&.id if association_reflection.nil? || reflection.options[:exec_context] == :decorator case reflection.type when :belongs_to compute_belongs_to_fk when :has_one compute_has_one_fk else fail "Cannot compute primary key for #{reflection.type} association" end end
class Pragma::Decorator::Association::Adapter::ActiveRecord
The ActiveRecord
association adapter is used in AR environments and tries to minimize the number of SQL queries that are made to retrieve the associated object's data.
@api private
Public Class Methods
Initializes the adapter.
@param bond [Bond] the bond to use in the adapter
@raise [InconsistentTypeError] when the association's real type is different from the
one defined on the decorator ()e.g. decorator defines the association as +belongs_to+, but ActiveRecord reports its type is +has_one+)
# File lib/pragma/decorator/association/adapter/active_record.rb, line 33 def initialize(bond) super check_type_consistency end
Returns whether the adapter supports the given bond.
@param bond [Bond] the bond to check
@return [Boolean] whether the object is an instance of ActiveRecord::Base
# File lib/pragma/decorator/association/adapter/active_record.rb, line 20 def supports?(bond) Object.const_defined?('::ActiveRecord::Base') && bond.model.is_a?(::ActiveRecord::Base) end
Public Instance Methods
Returns the expanded associated object.
This will simply return the associated object itself, delegating caching to AR.
@return [Object] the associated object
@todo Ensure the required attributes are present on the associated object
# File lib/pragma/decorator/association/adapter/active_record.rb, line 87 def full_object associated_object end
Returns the primary key of the associated object.
If the exec_context
of the association is decorator
, this will simply return early with the value returned by #id
on the associated object.
If the association is a belongs_to
, there are three possible scenarios:
* the association does not have a custom scope: this will compute the PK by calling the foreign key on the parent model; * the association has a custom scope and it has not been loaded: this will compute the PK by +pluck+ing the PK column of the associated object; * the association has a custom scope and it has been loaded: this will compute the PK by retrieving the PK attribute from the loaded object.
If the association is a has_one
, there are two possible scenarios:
* the association has already been loaded: this will compute the PK by retrieving the PK attribute from the loaded object; * the association has not been loaded: this will compute the PK by +pluck+ing the PK column of the associated object;
Custom scopes are always respected in both belongs_to
and has_one
.
nil
values are handled gracefully in all cases.
@return [String|Integer|NilClass] the PK of the associated object
@todo Allow to specify a different PK attribute when exec_context
is decorator
Private Instance Methods
# File lib/pragma/decorator/association/adapter/active_record.rb, line 135 def association_reflection @association_reflection ||= model.class.reflect_on_association(reflection.attribute) end
# File lib/pragma/decorator/association/adapter/active_record.rb, line 139 def check_type_consistency return unless association_reflection return if association_reflection.macro.to_sym == reflection.type.to_sym fail InconsistentTypeError.new( decorator: decorator, reflection: reflection, model_type: association_reflection.macro ) end
# File lib/pragma/decorator/association/adapter/active_record.rb, line 93 def compute_belongs_to_fk primary_key = if association_reflection.polymorphic? association_reflection.options[:primary_key] || associated_object.class.primary_key else association_reflection.association_primary_key end if model.association(reflection.attribute).loaded? return associated_object&.public_send(primary_key) end if association_reflection.scope.nil? return model.public_send(association_reflection.foreign_key) end pluck_association_fk do |scope| fk = model.public_send(association_reflection.foreign_key) scope.where(primary_key => fk) end end
# File lib/pragma/decorator/association/adapter/active_record.rb, line 114 def compute_has_one_fk if model.association(reflection.attribute).loaded? return associated_object&.public_send(association_reflection.association_primary_key) end pluck_association_fk do |scope| pk = model.public_send(association_reflection.active_record_primary_key) scope.where(association_reflection.foreign_key => pk) end end
# File lib/pragma/decorator/association/adapter/active_record.rb, line 125 def pluck_association_fk scope = association_reflection.klass.all if association_reflection.scope scope = scope.instance_eval(&association_reflection.scope) end yield(scope).pluck(association_reflection.association_primary_key).first end