module Sequel::Model::Associations::InstanceMethods
Instance methods used to implement the associations support.
Public Instance Methods
Source
# File lib/sequel/model/associations.rb 2514 def associations 2515 @associations ||= {} 2516 end
The currently cached associations. A hash with the keys being the association name symbols and the values being the associated object or nil (many_to_one), or the array of associated objects (*_to_many).
Source
# File lib/sequel/model/associations.rb 2521 def freeze 2522 associations 2523 super 2524 associations.freeze 2525 self 2526 end
Freeze the associations cache when freezing the object. Note that retrieving associations after freezing will still work in most cases, but the associations will not be cached in the association cache.
Private Instance Methods
Source
# File lib/sequel/model/associations.rb 2531 def _apply_association_options(opts, ds) 2532 unless ds.kind_of?(AssociationDatasetMethods) 2533 ds = opts.apply_dataset_changes(ds) 2534 end 2535 ds = ds.clone(:model_object => self) 2536 ds = ds.eager_graph(opts[:eager_graph]) if opts[:eager_graph] && opts.eager_graph_lazy_dataset? 2537 # block method is private 2538 ds = send(opts[:block_method], ds) if opts[:block_method] 2539 ds 2540 end
Apply the association options such as :order and :limit to the given dataset, returning a modified dataset.
Source
# File lib/sequel/model/associations.rb 2543 def _associated_dataset(opts, dynamic_opts) 2544 ds = public_send(opts.dataset_method) 2545 if callback = dynamic_opts[:callback] 2546 ds = callback.call(ds) 2547 end 2548 ds 2549 end
Return a dataset for the association after applying any dynamic callback.
Source
# File lib/sequel/model/associations.rb 2552 def _associated_object_loader(opts, dynamic_opts) 2553 if !dynamic_opts[:callback] && (loader = opts.placeholder_loader) 2554 loader 2555 end 2556 end
A placeholder literalizer that can be used to load the association, or nil to not use one.
Source
# File lib/sequel/model/associations.rb 2559 def _dataset(opts) 2560 raise(Sequel::Error, "model object #{inspect} does not have a primary key") if opts.dataset_need_primary_key? && !pk 2561 ds = if opts[:dataset_opt_arity] == 1 2562 # dataset_opt_method is private 2563 send(opts[:dataset_opt_method], opts) 2564 else 2565 send(opts[:dataset_opt_method]) 2566 end 2567 _apply_association_options(opts, ds) 2568 end
Return an association dataset for the given association reflection
Source
# File lib/sequel/model/associations.rb 2571 def _join_table_dataset(opts) 2572 ds = (opts[:join_table_db] || model.db).from(opts.join_table_source) 2573 opts[:join_table_block] ? opts[:join_table_block].call(ds) : ds 2574 end
Dataset
for the join table of the given many to many association reflection
Source
# File lib/sequel/model/associations.rb 2578 def _load_associated_object(opts, dynamic_opts) 2579 _load_associated_object_array(opts, dynamic_opts).first 2580 end
Return the associated single object for the given association reflection and dynamic options (or nil if no associated object).
Source
# File lib/sequel/model/associations.rb 2589 def _load_associated_object_array(opts, dynamic_opts) 2590 if loader = _associated_object_loader(opts, dynamic_opts) 2591 loader.all(*opts.predicate_key_values(self)) 2592 else 2593 ds = _associated_dataset(opts, dynamic_opts) 2594 if ds.opts[:no_results] 2595 [] 2596 else 2597 ds.all 2598 end 2599 end 2600 end
Load the associated objects for the given association reflection and dynamic options as an array.
Source
# File lib/sequel/model/associations.rb 2583 def _load_associated_object_via_primary_key(opts) 2584 opts.associated_class.send(:primary_key_lookup, ((fk = opts[:key]).is_a?(Array) ? fk.map{|c| get_column_value(c)} : get_column_value(fk))) 2585 end
Return the associated single object using a primary key lookup on the associated class.
Source
# File lib/sequel/model/associations.rb 2604 def _load_associated_objects(opts, dynamic_opts=OPTS) 2605 if opts.can_have_associated_objects?(self) 2606 if opts.returns_array? 2607 _load_associated_object_array(opts, dynamic_opts) 2608 elsif load_with_primary_key_lookup?(opts, dynamic_opts) 2609 _load_associated_object_via_primary_key(opts) 2610 else 2611 _load_associated_object(opts, dynamic_opts) 2612 end 2613 elsif opts.returns_array? 2614 [] 2615 end 2616 end
Return the associated objects from the dataset, without association callbacks, reciprocals, and caching. Still apply the dynamic callback if present.
Source
# File lib/sequel/model/associations.rb 2619 def _refresh_set_values(hash) 2620 @associations.clear if @associations 2621 super 2622 end
Clear the associations cache when refreshing
Source
# File lib/sequel/model/associations.rb 2861 def _set_associated_object(opts, o) 2862 a = associations[opts[:name]] 2863 reciprocal = opts.reciprocal 2864 if set_associated_object_if_same? 2865 if reciprocal 2866 remove_reciprocal = a && (a != o || a.associations[reciprocal] != self) 2867 add_reciprocal = o && o.associations[reciprocal] != self 2868 end 2869 else 2870 return if a && a == o 2871 if reciprocal 2872 remove_reciprocal = a 2873 add_reciprocal = o 2874 end 2875 end 2876 run_association_callbacks(opts, :before_set, o) 2877 remove_reciprocal_object(opts, a) if remove_reciprocal 2878 # Allow calling private _setter method 2879 send(opts[:_setter_method], o) 2880 associations[opts[:name]] = o 2881 add_reciprocal_object(opts, o) if add_reciprocal 2882 run_association_callbacks(opts, :after_set, o) 2883 o 2884 end
Set the given object as the associated object for the given *_to_one association reflection
Source
# File lib/sequel/model/associations.rb 2625 def add_associated_object(opts, o, *args) 2626 o = make_add_associated_object(opts, o) 2627 raise(Sequel::Error, "model object #{inspect} does not have a primary key") if opts.dataset_need_primary_key? && !pk 2628 ensure_associated_primary_key(opts, o, *args) 2629 return if run_association_callbacks(opts, :before_add, o) == false 2630 # Allow calling private _add method 2631 return if !send(opts[:_add_method], o, *args) && opts.handle_silent_modification_failure? 2632 if array = associations[opts[:name]] and !array.include?(o) 2633 array.push(o) 2634 end 2635 add_reciprocal_object(opts, o) 2636 run_association_callbacks(opts, :after_add, o) 2637 o 2638 end
Add the given associated object to the given association
Source
# File lib/sequel/model/associations.rb 2644 def add_reciprocal_object(opts, o) 2645 return if o.frozen? 2646 return unless reciprocal = opts.reciprocal 2647 if opts.reciprocal_array? 2648 if array = o.associations[reciprocal] and !array.include?(self) 2649 array.push(self) 2650 end 2651 else 2652 o.associations[reciprocal] = self 2653 end 2654 end
Add/Set the current object to/as the given object’s reciprocal association.
Source
# File lib/sequel/model/associations.rb 2658 def array_uniq!(a) 2659 a.uniq! 2660 end
Call uniq! on the given array. This is used by the :uniq option, and is an actual method for memory reasons.
Source
# File lib/sequel/model/associations.rb 2664 def change_column_value(column, value) 2665 if assocs = model.autoreloading_associations[column] 2666 vals = @values 2667 if new? 2668 # Do deeper checking for new objects, so that associations are 2669 # not deleted when values do not change. This code is run at 2670 # a higher level for existing objects. 2671 if value == (c = vals[column]) && value.class == c.class 2672 # If the value is the same, there is no reason to delete 2673 # the related associations, so exit early in that case. 2674 return super 2675 end 2676 2677 only_delete_nil = c.nil? 2678 elsif vals[column].nil? 2679 only_delete_nil = true 2680 end 2681 2682 if only_delete_nil 2683 # If the current foreign key value is nil, but the association 2684 # is already present in the cache, it was probably added to the 2685 # cache for a reason, and we do not want to delete it in that case. 2686 # However, we still want to delete associations with nil values 2687 # to remove the cached false negative. 2688 assocs.each{|a| associations.delete(a) if associations[a].nil?} 2689 else 2690 assocs.each{|a| associations.delete(a)} 2691 end 2692 end 2693 super 2694 end
If a foreign key column value changes, clear the related cached associations.
Source
# File lib/sequel/model/associations.rb 2699 def ensure_associated_primary_key(opts, o, *args) 2700 if opts.need_associated_primary_key? 2701 o.save(:validate=>opts[:validate]) if o.new? 2702 raise(Sequel::Error, "associated object #{o.inspect} does not have a primary key") unless o.pk 2703 end 2704 end
Save the associated object if the associated object needs a primary key and the associated object is new and does not have one. Raise an error if the object still does not have a primary key
Source
# File lib/sequel/model/associations.rb 2707 def initialize_copy(other) 2708 super 2709 @associations = Hash[@associations] if @associations 2710 self 2711 end
Duplicate the associations hash when duplicating the object.
Source
# File lib/sequel/model/associations.rb 2724 def load_associated_objects(opts, dynamic_opts, &block) 2725 dynamic_opts = load_association_objects_options(dynamic_opts, &block) 2726 name = opts[:name] 2727 if associations.include?(name) && !dynamic_opts[:callback] && !dynamic_opts[:reload] 2728 associations[name] 2729 else 2730 objs = _load_associated_objects(opts, dynamic_opts) 2731 if opts.set_reciprocal_to_self? 2732 if opts.returns_array? 2733 objs.each{|o| add_reciprocal_object(opts, o)} 2734 elsif objs 2735 add_reciprocal_object(opts, objs) 2736 end 2737 end 2738 2739 # If the current object is frozen, you can't update the associations 2740 # cache. This can cause issues for after_load procs that expect 2741 # the objects to be already cached in the associations, but 2742 # unfortunately that case cannot be handled. 2743 associations[name] = objs unless frozen? 2744 run_association_callbacks(opts, :after_load, objs) 2745 frozen? ? objs : associations[name] 2746 end 2747 end
Load the associated objects using the dataset, handling callbacks, reciprocals, and caching.
Source
# File lib/sequel/model/associations.rb 2714 def load_association_objects_options(dynamic_opts, &block) 2715 if block 2716 dynamic_opts = Hash[dynamic_opts] 2717 dynamic_opts[:callback] = block 2718 end 2719 2720 dynamic_opts 2721 end
If a block is given, assign it as the :callback option in the hash, and return the hash.
Source
# File lib/sequel/model/associations.rb 2750 def load_with_primary_key_lookup?(opts, dynamic_opts) 2751 opts[:type] == :many_to_one && 2752 !dynamic_opts[:callback] && 2753 opts.send(:cached_fetch, :many_to_one_pk_lookup){opts.primary_key == opts.associated_class.primary_key} 2754 end
Whether to use a simple primary key lookup on the associated class when loading.
Source
# File lib/sequel/model/associations.rb 2760 def make_add_associated_object(opts, o) 2761 klass = opts.associated_class 2762 2763 case o 2764 when Hash 2765 klass.new(o) 2766 when Integer, String, Array 2767 klass.with_pk!(o) 2768 when klass 2769 o 2770 else 2771 raise(Sequel::Error, "associated object #{o.inspect} not of correct type #{klass}") 2772 end 2773 end
Convert the input of the add_* association method into an associated object. For hashes, this creates a new object using the hash. For integers, strings, and arrays, assume the value specifies a primary key, and lookup an existing object with that primary key. Otherwise, if the object is not already an instance of the class, raise an exception.
Source
# File lib/sequel/model/associations.rb 2776 def remove_all_associated_objects(opts, *args) 2777 raise(Sequel::Error, "model object #{inspect} does not have a primary key") if opts.dataset_need_primary_key? && !pk 2778 # Allow calling private _remove_all method 2779 send(opts[:_remove_all_method], *args) 2780 ret = associations[opts[:name]].each{|o| remove_reciprocal_object(opts, o)} if associations.include?(opts[:name]) 2781 associations[opts[:name]] = [] 2782 ret 2783 end
Remove all associated objects from the given association
Source
# File lib/sequel/model/associations.rb 2789 def remove_associated_object(opts, o, *args) 2790 klass = opts.associated_class 2791 if o.is_a?(Integer) || o.is_a?(String) || o.is_a?(Array) 2792 o = remove_check_existing_object_from_pk(opts, o, *args) 2793 elsif !o.is_a?(klass) 2794 raise(Sequel::Error, "associated object #{o.inspect} not of correct type #{klass}") 2795 elsif opts.remove_should_check_existing? && public_send(opts.dataset_method).where(o.pk_hash).empty? 2796 raise(Sequel::Error, "associated object #{o.inspect} is not currently associated to #{inspect}") 2797 end 2798 raise(Sequel::Error, "model object #{inspect} does not have a primary key") if opts.dataset_need_primary_key? && !pk 2799 raise(Sequel::Error, "associated object #{o.inspect} does not have a primary key") if opts.need_associated_primary_key? && !o.pk 2800 return if run_association_callbacks(opts, :before_remove, o) == false 2801 # Allow calling private _remove method 2802 return if !send(opts[:_remove_method], o, *args) && opts.handle_silent_modification_failure? 2803 associations[opts[:name]].delete_if{|x| o === x} if associations.include?(opts[:name]) 2804 remove_reciprocal_object(opts, o) 2805 run_association_callbacks(opts, :after_remove, o) 2806 o 2807 end
Remove the given associated object from the given association
Source
# File lib/sequel/model/associations.rb 2815 def remove_check_existing_object_from_pk(opts, o, *args) 2816 key = o 2817 pkh = opts.associated_class.qualified_primary_key_hash(key) 2818 raise(Sequel::Error, "no object with key(s) #{key.inspect} is currently associated to #{inspect}") unless o = public_send(opts.dataset_method).first(pkh) 2819 o 2820 end
Check that the object from the associated table specified by the primary key is currently associated to the receiver. If it is associated, return the object, otherwise raise an error.
Source
# File lib/sequel/model/associations.rb 2823 def remove_reciprocal_object(opts, o) 2824 return unless reciprocal = opts.reciprocal 2825 if opts.reciprocal_array? 2826 if array = o.associations[reciprocal] 2827 array.delete_if{|x| self === x} 2828 end 2829 else 2830 o.associations[reciprocal] = nil 2831 end 2832 end
Remove/unset the current object from/as the given object’s reciprocal association.
Source
# File lib/sequel/model/associations.rb 2835 def run_association_callbacks(reflection, callback_type, object) 2836 return unless cbs = reflection[callback_type] 2837 2838 begin 2839 cbs.each do |cb| 2840 case cb 2841 when Symbol 2842 # Allow calling private methods in association callbacks 2843 send(cb, object) 2844 when Proc 2845 cb.call(self, object) 2846 else 2847 raise Error, "callbacks should either be Procs or Symbols" 2848 end 2849 end 2850 rescue HookFailed 2851 # The reason we automatically set raise_error for singular associations is that 2852 # assignment in ruby always returns the argument instead of the result of the 2853 # method, so we can't return nil to signal that the association callback prevented 2854 # the modification 2855 return false unless raise_on_save_failure || !reflection.returns_array? 2856 raise 2857 end 2858 end
Run the callback for the association with the object.
Source
# File lib/sequel/model/associations.rb 2894 def set_associated_object(opts, o) 2895 raise(Error, "associated object #{o.inspect} does not have a primary key") if o && !o.pk 2896 _set_associated_object(opts, o) 2897 end
Set the given object as the associated object for the given many_to_one association reflection
Source
# File lib/sequel/model/associations.rb 2889 def set_associated_object_if_same? 2890 @set_associated_object_if_same 2891 end
Whether run the associated object setter code if passed the same object as the one already cached in the association. Usually not set (so nil), can be set on a per-object basis if necessary.
Source
# File lib/sequel/model/associations.rb 2900 def set_one_through_one_associated_object(opts, o) 2901 raise(Error, "object #{inspect} does not have a primary key") unless pk 2902 raise(Error, "associated object #{o.inspect} does not have a primary key") if o && !o.pk 2903 _set_associated_object(opts, o) 2904 end
Set the given object as the associated object for the given one_through_one association reflection
Source
# File lib/sequel/model/associations.rb 2907 def set_one_to_one_associated_object(opts, o) 2908 raise(Error, "object #{inspect} does not have a primary key") unless pk 2909 _set_associated_object(opts, o) 2910 end
Set the given object as the associated object for the given one_to_one association reflection