Module: Mongoid::Association::Accessors
- Extended by:
- ActiveSupport::Concern
- Included in:
- Mongoid::Association
- Defined in:
- lib/mongoid/association/accessors.rb
Overview
This module contains all the behavior related to accessing associations through the getters and setters, and how to delegate to builders to create new ones.
Class Method Summary collapse
-
.define_builder!(association) ⇒ Class
Defines a builder method for an embeds_one association.
-
.define_creator!(association) ⇒ Class
Defines a creator method for an embeds_one association.
-
.define_existence_check!(association) ⇒ Class
Adds the existence check for associations.
-
.define_getter!(association) ⇒ Class
Defines the getter for the association.
-
.define_ids_getter!(association) ⇒ Class
Defines the getter for the ids of documents in the association.
-
.define_ids_setter!(association) ⇒ Object
Defines the setter method that allows you to set documents in this association by their ids.
-
.define_setter!(association) ⇒ Class
Defines the setter for the association.
Instance Method Summary collapse
-
#__build__(name, object, association, selected_fields = nil) ⇒ Proxy
Builds the related document and creates the association unless the document is nil, then sets the association on this document.
-
#create_relation(object, association, selected_fields = nil) ⇒ Proxy
Create an association from an object and association metadata.
-
#reset_relation_criteria(name) ⇒ Object
Resets the criteria inside the association proxy.
-
#set_relation(name, relation) ⇒ Proxy
Set the supplied association to an instance variable on the class with the provided name.
Class Method Details
.define_builder!(association) ⇒ Class
Defines a builder method for an embeds_one association. This is defined as #build_name.
394 395 396 397 398 399 400 401 402 403 404 405 406 407 |
# File 'lib/mongoid/association/accessors.rb', line 394 def self.define_builder!(association) name = association.name association.inverse_class.tap do |klass| klass.re_define_method("build_#{name}") do |*args| attributes, = parse_args(*args) document = Factory.build(association.relation_class, attributes) _building do child = send("#{name}=", document) child.run_callbacks(:build) child end end end end |
.define_creator!(association) ⇒ Class
Defines a creator method for an embeds_one association. This is defined as #create_name. After the object is built it will immediately save.
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 |
# File 'lib/mongoid/association/accessors.rb', line 419 def self.define_creator!(association) name = association.name association.inverse_class.tap do |klass| klass.re_define_method("create_#{name}") do |*args| attributes, = parse_args(*args) document = Factory.build(association.klass, attributes) doc = _assigning do send("#{name}=", document) end doc.save save if new_record? && association.stores_foreign_key? doc end end end |
.define_existence_check!(association) ⇒ Class
Adds the existence check for associations.
280 281 282 283 284 285 286 287 288 289 290 |
# File 'lib/mongoid/association/accessors.rb', line 280 def self.define_existence_check!(association) name = association.name association.inverse_class.tap do |klass| klass.module_eval <<-END, __FILE__, __LINE__ + 1 def #{name}? without_autobuild { !__send__(:#{name}).blank? } end alias :has_#{name}? :#{name}? END end end |
.define_getter!(association) ⇒ Class
Defines the getter for the association. Nothing too special here: just return the instance variable for the association if it exists or build the thing.
302 303 304 305 306 307 308 309 310 311 312 313 |
# File 'lib/mongoid/association/accessors.rb', line 302 def self.define_getter!(association) name = association.name association.inverse_class.tap do |klass| klass.re_define_method(name) do |reload = false| value = get_relation(name, association, nil, reload) if value.nil? && association.autobuilding? && !without_autobuild? value = send("build_#{name}") end value end end end |
.define_ids_getter!(association) ⇒ Class
Defines the getter for the ids of documents in the association. Should be specify only for referenced many associations.
324 325 326 327 328 329 330 331 |
# File 'lib/mongoid/association/accessors.rb', line 324 def self.define_ids_getter!(association) ids_method = "#{association.name.to_s.singularize}_ids" association.inverse_class.tap do |klass| klass.re_define_method(ids_method) do send(association.name).pluck(:_id) end end end |
.define_ids_setter!(association) ⇒ Object
Defines the setter method that allows you to set documents in this association by their ids. The defined setter, finds documents with given ids and invokes regular association setter with found documents. Ids setters should be defined only for referenced many associations.
@param [ Mongoid::Association::Relatable ] association The association for the association.
@return [ Class ] The class being set up.
375 376 377 378 379 380 381 382 383 |
# File 'lib/mongoid/association/accessors.rb', line 375 def self.define_ids_setter!(association) ids_method = "#{association.name.to_s.singularize}_ids=" association.inverse_class.aliased_associations[ids_method.chop] = association.name.to_s association.inverse_class.tap do |klass| klass.re_define_method(ids_method) do |ids| send(association.setter, association.relation_class.find(ids.reject(&:blank?))) end end end |
.define_setter!(association) ⇒ Class
Defines the setter for the association. This does a few things based on some conditions. If there is an existing association, a target substitution will take place, otherwise a new association will be created with the supplied target.
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 |
# File 'lib/mongoid/association/accessors.rb', line 344 def self.define_setter!(association) name = association.name association.inverse_class.tap do |klass| klass.re_define_method("#{name}=") do |object| without_autobuild do if value = get_relation(name, association, object) if !value.respond_to?(:substitute) value = __build__(name, value, association) end set_relation(name, value.substitute(object.substitutable)) else __build__(name, object.substitutable, association) end end end end end |
Instance Method Details
#__build__(name, object, association, selected_fields = nil) ⇒ Proxy
Builds the related document and creates the association unless the document is nil, then sets the association on this document.
27 28 29 30 |
# File 'lib/mongoid/association/accessors.rb', line 27 def __build__(name, object, association, selected_fields = nil) relation = create_relation(object, association, selected_fields) set_relation(name, relation) end |
#create_relation(object, association, selected_fields = nil) ⇒ Proxy
Create an association from an object and association metadata.
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/mongoid/association/accessors.rb', line 44 def create_relation(object, association, selected_fields = nil) key = @attributes[association.inverse_type] type = key ? association.resolver.model_for(key) : nil target = if t = association.build(self, object, type, selected_fields) association.create_relation(self, t) else nil end # Only need to do this on embedded associations. The pending callbacks # are only added when materializing the documents, which only happens # on embedded associations. There is no call to the database in the # construction of a referenced association. if association. Array(target).each do |doc| doc.try(:run_pending_callbacks) end end target end |
#reset_relation_criteria(name) ⇒ Object
Resets the criteria inside the association proxy. Used by many-to-many associations to keep the underlying ids array in sync.
73 74 75 76 77 |
# File 'lib/mongoid/association/accessors.rb', line 73 def reset_relation_criteria(name) if instance_variable_defined?("@_#{name}") send(name).reset_unloaded end end |
#set_relation(name, relation) ⇒ Proxy
Set the supplied association to an instance variable on the class with the provided name. Used as a helper just for code cleanliness.
89 90 91 |
# File 'lib/mongoid/association/accessors.rb', line 89 def set_relation(name, relation) instance_variable_set("@_#{name}", relation) end |