Class: DuckRecord::Associations::Association
- Inherits:
-
Object
- Object
- DuckRecord::Associations::Association
- Defined in:
- lib/duck_record/associations/association.rb
Overview
Active Record Associations
This is the root class of all associations (‘+ Foo’ signifies an included module Foo):
Association
SingularAssociation
HasOneAssociation + ForeignAssociation
HasOneThroughAssociation + ThroughAssociation
BelongsToAssociation
BelongsToPolymorphicAssociation
CollectionAssociation
HasManyAssociation + ForeignAssociation
HasManyThroughAssociation + ThroughAssociation
Direct Known Subclasses
Instance Attribute Summary collapse
-
#owner ⇒ Object
readonly
:nodoc:.
-
#reflection ⇒ Object
readonly
:nodoc:.
-
#target ⇒ Object
:nodoc:.
Instance Method Summary collapse
-
#aliased_table_name ⇒ Object
Returns the name of the table of the associated class:.
-
#association_scope ⇒ Object
The scope for this association.
- #create(attributes = {}, &block) ⇒ Object
- #create!(attributes = {}, &block) ⇒ Object
- #extensions ⇒ Object
-
#initialize(owner, reflection) ⇒ Association
constructor
A new instance of Association.
-
#initialize_attributes(record, except_from_scope_attributes = nil) ⇒ Object
:nodoc:.
- #interpolate(sql, record = nil) ⇒ Object
-
#klass ⇒ Object
Returns the class of the target.
-
#load_target ⇒ Object
Loads the target if needed and returns it.
-
#loaded! ⇒ Object
Asserts the target has been loaded setting the loaded flag to
true. -
#loaded? ⇒ Boolean
Has the target been already loaded?.
-
#marshal_dump ⇒ Object
We can’t dump @reflection since it contains the scope proc.
- #marshal_load(data) ⇒ Object
-
#reload ⇒ Object
Reloads the target and returns
selfon success. -
#remove_inverse_instance(_record) ⇒ Object
Remove the inverse association, if possible.
-
#reset ⇒ Object
Resets the loaded flag to
falseand sets the target tonil. - #reset_scope ⇒ Object
- #scope ⇒ Object
-
#set_inverse_instance(record) ⇒ Object
Set the inverse association, if possible.
-
#stale_target? ⇒ Boolean
The target is stale if the target no longer points to the record(s) that the relevant foreign_key(s) refers to.
-
#target_scope ⇒ Object
Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the through association’s scope).
Constructor Details
#initialize(owner, reflection) ⇒ Association
Returns a new instance of Association.
23 24 25 26 27 28 29 30 |
# File 'lib/duck_record/associations/association.rb', line 23 def initialize(owner, reflection) reflection.check_validity! @owner, @reflection = owner, reflection reset reset_scope end |
Instance Attribute Details
#owner ⇒ Object (readonly)
:nodoc:
19 20 21 |
# File 'lib/duck_record/associations/association.rb', line 19 def owner @owner end |
#reflection ⇒ Object (readonly)
:nodoc:
19 20 21 |
# File 'lib/duck_record/associations/association.rb', line 19 def reflection @reflection end |
#target ⇒ Object
:nodoc:
19 20 21 |
# File 'lib/duck_record/associations/association.rb', line 19 def target @target end |
Instance Method Details
#aliased_table_name ⇒ Object
Returns the name of the table of the associated class:
post.comments.aliased_table_name # => "comments"
36 37 38 |
# File 'lib/duck_record/associations/association.rb', line 36 def aliased_table_name klass.table_name end |
#association_scope ⇒ Object
The scope for this association.
Note that the association_scope is merged into the target_scope only when the scope method is called. This is because at that point the call may be surrounded by scope.scoping { … } or with_scope { … } etc, which affects the scope which actually gets built.
92 93 94 95 96 97 98 |
# File 'lib/duck_record/associations/association.rb', line 92 def association_scope return unless klass @association_scope ||= ActiveRecord::Associations::AssociationScope.scope(self) rescue ArgumentError @association_scope ||= ActiveRecord::Associations::AssociationScope.scope(self, klass.connection) end |
#create(attributes = {}, &block) ⇒ Object
184 185 186 |
# File 'lib/duck_record/associations/association.rb', line 184 def create(attributes = {}, &block) _create_record(attributes, &block) end |
#create!(attributes = {}, &block) ⇒ Object
188 189 190 |
# File 'lib/duck_record/associations/association.rb', line 188 def create!(attributes = {}, &block) _create_record(attributes, true, &block) end |
#extensions ⇒ Object
126 127 128 129 130 131 132 133 134 |
# File 'lib/duck_record/associations/association.rb', line 126 def extensions extensions = klass.default_extensions | reflection.extensions if scope = reflection.scope extensions |= klass.unscoped.instance_exec(owner, &scope).extensions end extensions end |
#initialize_attributes(record, except_from_scope_attributes = nil) ⇒ Object
:nodoc:
175 176 177 178 179 180 181 182 |
# File 'lib/duck_record/associations/association.rb', line 175 def initialize_attributes(record, except_from_scope_attributes = nil) #:nodoc: except_from_scope_attributes ||= {} skip_assign = [reflection.foreign_key, reflection.type].compact assigned_keys = record.changed_attribute_names_to_save assigned_keys += except_from_scope_attributes.keys.map(&:to_s) attributes = create_scope.except(*(assigned_keys - skip_assign)) record.assign_attributes(attributes) end |
#interpolate(sql, record = nil) ⇒ Object
155 156 157 158 159 160 161 |
# File 'lib/duck_record/associations/association.rb', line 155 def interpolate(sql, record = nil) if sql.respond_to?(:to_proc) owner.instance_exec(record, &sql) else sql end end |
#klass ⇒ Object
Returns the class of the target. belongs_to polymorphic overrides this to look at the polymorphic_type field on the owner.
114 115 116 |
# File 'lib/duck_record/associations/association.rb', line 114 def klass reflection.klass end |
#load_target ⇒ Object
Loads the target if needed and returns it.
This method is abstract in the sense that it relies on find_target, which is expected to be provided by descendants.
If the target is already loaded it is just returned. Thus, you can call load_target unconditionally to get the target.
ActiveRecord::RecordNotFound is rescued within the method, and it is not reraised. The proxy is reset and nil is the return value.
146 147 148 149 150 151 152 153 |
# File 'lib/duck_record/associations/association.rb', line 146 def load_target @target = find_target if (@stale_state && stale_target?) || find_target? loaded! unless loaded? target rescue ActiveRecord::RecordNotFound reset end |
#loaded! ⇒ Object
Asserts the target has been loaded setting the loaded flag to true.
61 62 63 64 |
# File 'lib/duck_record/associations/association.rb', line 61 def loaded! @loaded = true @stale_state = stale_state end |
#loaded? ⇒ Boolean
Has the target been already loaded?
56 57 58 |
# File 'lib/duck_record/associations/association.rb', line 56 def loaded? @loaded end |
#marshal_dump ⇒ Object
We can’t dump @reflection since it contains the scope proc
164 165 166 167 |
# File 'lib/duck_record/associations/association.rb', line 164 def marshal_dump ivars = (instance_variables - [:@reflection]).map { |name| [name, instance_variable_get(name)] } [@reflection.name, ivars] end |
#marshal_load(data) ⇒ Object
169 170 171 172 173 |
# File 'lib/duck_record/associations/association.rb', line 169 def marshal_load(data) reflection_name, ivars = data ivars.each { |name, val| instance_variable_set(name, val) } @reflection = @owner.class._reflect_on_association(reflection_name) end |
#reload ⇒ Object
Reloads the target and returns self on success.
48 49 50 51 52 53 |
# File 'lib/duck_record/associations/association.rb', line 48 def reload reset reset_scope load_target self unless target.nil? end |
#remove_inverse_instance(_record) ⇒ Object
Remove the inverse association, if possible
110 |
# File 'lib/duck_record/associations/association.rb', line 110 def remove_inverse_instance(_record); end |
#reset ⇒ Object
Resets the loaded flag to false and sets the target to nil.
41 42 43 44 45 |
# File 'lib/duck_record/associations/association.rb', line 41 def reset @loaded = false @target = nil @stale_state = nil end |
#reset_scope ⇒ Object
100 101 102 |
# File 'lib/duck_record/associations/association.rb', line 100 def reset_scope @association_scope = nil end |
#scope ⇒ Object
82 83 84 |
# File 'lib/duck_record/associations/association.rb', line 82 def scope target_scope.merge!(association_scope) end |
#set_inverse_instance(record) ⇒ Object
Set the inverse association, if possible
105 106 107 |
# File 'lib/duck_record/associations/association.rb', line 105 def set_inverse_instance(record) record end |
#stale_target? ⇒ Boolean
The target is stale if the target no longer points to the record(s) that the relevant foreign_key(s) refers to. If stale, the association accessor method on the owner will reload the target. It’s up to subclasses to implement the stale_state method if relevant.
Note that if the target has not been loaded, it is not considered stale.
72 73 74 |
# File 'lib/duck_record/associations/association.rb', line 72 def stale_target? loaded? && @stale_state != stale_state end |
#target_scope ⇒ Object
Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the through association’s scope)
120 121 122 123 124 |
# File 'lib/duck_record/associations/association.rb', line 120 def target_scope ActiveRecord::AssociationRelation.create(klass, self).merge!(klass.all) rescue ArgumentError ActiveRecord::AssociationRelation.create(klass, klass.arel_table, klass.predicate_builder, self).merge!(klass.all) end |