module Sequel::Model::Associations::InstanceMethods
Instance methods used to implement the associations support.
Public Instance Methods
Source
# File lib/sequel/model/associations.rb 2696 def associations 2697 @associations ||= {} 2698 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 2703 def freeze 2704 associations 2705 super 2706 associations.freeze 2707 self 2708 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 2713 def _apply_association_options(opts, ds) 2714 unless ds.kind_of?(AssociationDatasetMethods) 2715 ds = opts.apply_dataset_changes(ds) 2716 end 2717 ds = ds.clone(:model_object => self) 2718 ds = ds.eager_graph(opts[:eager_graph]) if opts[:eager_graph] && opts.eager_graph_lazy_dataset? 2719 # block method is private 2720 ds = send(opts[:block_method], ds) if opts[:block_method] 2721 ds 2722 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 2725 def _associated_dataset(opts, dynamic_opts) 2726 ds = public_send(opts.dataset_method) 2727 if callback = dynamic_opts[:callback] 2728 ds = callback.call(ds) 2729 end 2730 ds 2731 end
Return a dataset for the association after applying any dynamic callback.
Source
# File lib/sequel/model/associations.rb 2734 def _associated_object_loader(opts, dynamic_opts) 2735 if !dynamic_opts[:callback] && (loader = opts.placeholder_loader) 2736 loader 2737 end 2738 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 2741 def _dataset(opts) 2742 raise(Sequel::Error, "model object #{inspect} does not have a primary key") if opts.dataset_need_primary_key? && !pk 2743 ds = if opts[:dataset_opt_arity] == 1 2744 # dataset_opt_method is private 2745 send(opts[:dataset_opt_method], opts) 2746 else 2747 send(opts[:dataset_opt_method]) 2748 end 2749 _apply_association_options(opts, ds) 2750 end
Return an association dataset for the given association reflection
Source
# File lib/sequel/model/associations.rb 2753 def _join_table_dataset(opts) 2754 ds = (opts[:join_table_db] || model.db).from(opts.join_table_source) 2755 opts[:join_table_block] ? opts[:join_table_block].call(ds) : ds 2756 end
Dataset for the join table of the given many to many association reflection
Source
# File lib/sequel/model/associations.rb 2760 def _load_associated_object(opts, dynamic_opts) 2761 _load_associated_object_array(opts, dynamic_opts).first 2762 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 2771 def _load_associated_object_array(opts, dynamic_opts) 2772 if loader = _associated_object_loader(opts, dynamic_opts) 2773 loader.all(*opts.predicate_key_values(self)) 2774 else 2775 ds = _associated_dataset(opts, dynamic_opts) 2776 if ds.opts[:no_results] 2777 [] 2778 else 2779 ds.all 2780 end 2781 end 2782 end
Load the associated objects for the given association reflection and dynamic options as an array.
Source
# File lib/sequel/model/associations.rb 2765 def _load_associated_object_via_primary_key(opts) 2766 opts.associated_class.send(:primary_key_lookup, ((fk = opts[:key]).is_a?(Array) ? fk.map{|c| get_column_value(c)} : get_column_value(fk))) 2767 end
Return the associated single object using a primary key lookup on the associated class.
Source
# File lib/sequel/model/associations.rb 2786 def _load_associated_objects(opts, dynamic_opts=OPTS) 2787 if opts.can_have_associated_objects?(self) 2788 if opts.returns_array? 2789 _load_associated_object_array(opts, dynamic_opts) 2790 elsif load_with_primary_key_lookup?(opts, dynamic_opts) 2791 _load_associated_object_via_primary_key(opts) 2792 else 2793 _load_associated_object(opts, dynamic_opts) 2794 end 2795 elsif opts.returns_array? 2796 [] 2797 end 2798 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 2801 def _refresh_set_values(hash) 2802 @associations.clear if @associations 2803 super 2804 end
Clear the associations cache when refreshing
Source
# File lib/sequel/model/associations.rb 3043 def _set_associated_object(opts, o) 3044 a = associations[opts[:name]] 3045 reciprocal = opts.reciprocal 3046 if set_associated_object_if_same? 3047 if reciprocal 3048 remove_reciprocal = a && (a != o || a.associations[reciprocal] != self) 3049 add_reciprocal = o && o.associations[reciprocal] != self 3050 end 3051 else 3052 return if a && a == o 3053 if reciprocal 3054 remove_reciprocal = a 3055 add_reciprocal = o 3056 end 3057 end 3058 run_association_callbacks(opts, :before_set, o) 3059 remove_reciprocal_object(opts, a) if remove_reciprocal 3060 # Allow calling private _setter method 3061 send(opts[:_setter_method], o) 3062 associations[opts[:name]] = o 3063 add_reciprocal_object(opts, o) if add_reciprocal 3064 run_association_callbacks(opts, :after_set, o) 3065 o 3066 end
Set the given object as the associated object for the given *_to_one association reflection
Source
# File lib/sequel/model/associations.rb 2807 def add_associated_object(opts, o, *args) 2808 o = make_add_associated_object(opts, o) 2809 raise(Sequel::Error, "model object #{inspect} does not have a primary key") if opts.dataset_need_primary_key? && !pk 2810 ensure_associated_primary_key(opts, o, *args) 2811 return if run_association_callbacks(opts, :before_add, o) == false 2812 # Allow calling private _add method 2813 return if !send(opts[:_add_method], o, *args) && opts.handle_silent_modification_failure? 2814 if array = associations[opts[:name]] and !array.include?(o) 2815 array.push(o) 2816 end 2817 add_reciprocal_object(opts, o) 2818 run_association_callbacks(opts, :after_add, o) 2819 o 2820 end
Add the given associated object to the given association
Source
# File lib/sequel/model/associations.rb 2826 def add_reciprocal_object(opts, o) 2827 return if o.frozen? 2828 return unless reciprocal = opts.reciprocal 2829 if opts.reciprocal_array? 2830 if array = o.associations[reciprocal] and !array.include?(self) 2831 array.push(self) 2832 end 2833 else 2834 o.associations[reciprocal] = self 2835 end 2836 end
Add/Set the current object to/as the given object’s reciprocal association.
Source
# File lib/sequel/model/associations.rb 2840 def array_uniq!(a) 2841 a.uniq! 2842 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 2846 def change_column_value(column, value) 2847 if assocs = model.autoreloading_associations[column] 2848 vals = @values 2849 if new? 2850 # Do deeper checking for new objects, so that associations are 2851 # not deleted when values do not change. This code is run at 2852 # a higher level for existing objects. 2853 if value == (c = vals[column]) && value.class == c.class 2854 # If the value is the same, there is no reason to delete 2855 # the related associations, so exit early in that case. 2856 return super 2857 end 2858 2859 only_delete_nil = c.nil? 2860 elsif vals[column].nil? 2861 only_delete_nil = true 2862 end 2863 2864 if only_delete_nil 2865 # If the current foreign key value is nil, but the association 2866 # is already present in the cache, it was probably added to the 2867 # cache for a reason, and we do not want to delete it in that case. 2868 # However, we still want to delete associations with nil values 2869 # to remove the cached false negative. 2870 assocs.each{|a| associations.delete(a) if associations[a].nil?} 2871 else 2872 assocs.each{|a| associations.delete(a)} 2873 end 2874 end 2875 super 2876 end
If a foreign key column value changes, clear the related cached associations.
Source
# File lib/sequel/model/associations.rb 2881 def ensure_associated_primary_key(opts, o, *args) 2882 if opts.need_associated_primary_key? 2883 o.save(:validate=>opts[:validate]) if o.new? 2884 raise(Sequel::Error, "associated object #{o.inspect} does not have a primary key") unless o.pk 2885 end 2886 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 2889 def initialize_copy(other) 2890 super 2891 @associations = Hash[@associations] if @associations 2892 self 2893 end
Duplicate the associations hash when duplicating the object.
Source
# File lib/sequel/model/associations.rb 2906 def load_associated_objects(opts, dynamic_opts, &block) 2907 dynamic_opts = load_association_objects_options(dynamic_opts, &block) 2908 name = opts[:name] 2909 if associations.include?(name) && !dynamic_opts[:callback] && !dynamic_opts[:reload] 2910 associations[name] 2911 else 2912 objs = _load_associated_objects(opts, dynamic_opts) 2913 if opts.set_reciprocal_to_self? 2914 if opts.returns_array? 2915 objs.each{|o| add_reciprocal_object(opts, o)} 2916 elsif objs 2917 add_reciprocal_object(opts, objs) 2918 end 2919 end 2920 2921 # If the current object is frozen, you can't update the associations 2922 # cache. This can cause issues for after_load procs that expect 2923 # the objects to be already cached in the associations, but 2924 # unfortunately that case cannot be handled. 2925 associations[name] = objs unless frozen? 2926 run_association_callbacks(opts, :after_load, objs) 2927 frozen? ? objs : associations[name] 2928 end 2929 end
Load the associated objects using the dataset, handling callbacks, reciprocals, and caching.
Source
# File lib/sequel/model/associations.rb 2896 def load_association_objects_options(dynamic_opts, &block) 2897 if block 2898 dynamic_opts = Hash[dynamic_opts] 2899 dynamic_opts[:callback] = block 2900 end 2901 2902 dynamic_opts 2903 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 2932 def load_with_primary_key_lookup?(opts, dynamic_opts) 2933 opts[:type] == :many_to_one && 2934 !dynamic_opts[:callback] && 2935 opts.send(:cached_fetch, :many_to_one_pk_lookup){opts.primary_key == opts.associated_class.primary_key} 2936 end
Whether to use a simple primary key lookup on the associated class when loading.
Source
# File lib/sequel/model/associations.rb 2942 def make_add_associated_object(opts, o) 2943 klass = opts.associated_class 2944 2945 case o 2946 when Hash 2947 klass.new(o) 2948 when Integer, String, Array 2949 klass.with_pk!(o) 2950 when klass 2951 o 2952 else 2953 raise(Sequel::Error, "associated object #{o.inspect} not of correct type #{klass}") 2954 end 2955 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 2958 def remove_all_associated_objects(opts, *args) 2959 raise(Sequel::Error, "model object #{inspect} does not have a primary key") if opts.dataset_need_primary_key? && !pk 2960 # Allow calling private _remove_all method 2961 send(opts[:_remove_all_method], *args) 2962 ret = associations[opts[:name]].each{|o| remove_reciprocal_object(opts, o)} if associations.include?(opts[:name]) 2963 associations[opts[:name]] = [] 2964 ret 2965 end
Remove all associated objects from the given association
Source
# File lib/sequel/model/associations.rb 2971 def remove_associated_object(opts, o, *args) 2972 klass = opts.associated_class 2973 if o.is_a?(Integer) || o.is_a?(String) || o.is_a?(Array) 2974 o = remove_check_existing_object_from_pk(opts, o, *args) 2975 elsif !o.is_a?(klass) 2976 raise(Sequel::Error, "associated object #{o.inspect} not of correct type #{klass}") 2977 elsif opts.remove_should_check_existing? && public_send(opts.dataset_method).where(o.pk_hash).empty? 2978 raise(Sequel::Error, "associated object #{o.inspect} is not currently associated to #{inspect}") 2979 end 2980 raise(Sequel::Error, "model object #{inspect} does not have a primary key") if opts.dataset_need_primary_key? && !pk 2981 raise(Sequel::Error, "associated object #{o.inspect} does not have a primary key") if opts.need_associated_primary_key? && !o.pk 2982 return if run_association_callbacks(opts, :before_remove, o) == false 2983 # Allow calling private _remove method 2984 return if !send(opts[:_remove_method], o, *args) && opts.handle_silent_modification_failure? 2985 associations[opts[:name]].delete_if{|x| o === x} if associations.include?(opts[:name]) 2986 remove_reciprocal_object(opts, o) 2987 run_association_callbacks(opts, :after_remove, o) 2988 o 2989 end
Remove the given associated object from the given association
Source
# File lib/sequel/model/associations.rb 2997 def remove_check_existing_object_from_pk(opts, o, *args) 2998 key = o 2999 pkh = opts.associated_class.qualified_primary_key_hash(key) 3000 raise(Sequel::Error, "no object with key(s) #{key.inspect} is currently associated to #{inspect}") unless o = public_send(opts.dataset_method).first(pkh) 3001 o 3002 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 3005 def remove_reciprocal_object(opts, o) 3006 return unless reciprocal = opts.reciprocal 3007 if opts.reciprocal_array? 3008 if array = o.associations[reciprocal] 3009 array.delete_if{|x| self === x} 3010 end 3011 else 3012 o.associations[reciprocal] = nil 3013 end 3014 end
Remove/unset the current object from/as the given object’s reciprocal association.
Source
# File lib/sequel/model/associations.rb 3017 def run_association_callbacks(reflection, callback_type, object) 3018 return unless cbs = reflection[callback_type] 3019 3020 begin 3021 cbs.each do |cb| 3022 case cb 3023 when Symbol 3024 # Allow calling private methods in association callbacks 3025 send(cb, object) 3026 when Proc 3027 cb.call(self, object) 3028 else 3029 raise Error, "callbacks should either be Procs or Symbols" 3030 end 3031 end 3032 rescue HookFailed 3033 # The reason we automatically set raise_error for singular associations is that 3034 # assignment in ruby always returns the argument instead of the result of the 3035 # method, so we can't return nil to signal that the association callback prevented 3036 # the modification 3037 return false unless raise_on_save_failure || !reflection.returns_array? 3038 raise 3039 end 3040 end
Run the callback for the association with the object.
Source
# File lib/sequel/model/associations.rb 3076 def set_associated_object(opts, o) 3077 raise(Error, "associated object #{o.inspect} does not have a primary key") if o && !o.pk 3078 _set_associated_object(opts, o) 3079 end
Set the given object as the associated object for the given many_to_one association reflection
Source
# File lib/sequel/model/associations.rb 3071 def set_associated_object_if_same? 3072 @set_associated_object_if_same 3073 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 3082 def set_one_through_one_associated_object(opts, o) 3083 raise(Error, "object #{inspect} does not have a primary key") unless pk 3084 raise(Error, "associated object #{o.inspect} does not have a primary key") if o && !o.pk 3085 _set_associated_object(opts, o) 3086 end
Set the given object as the associated object for the given one_through_one association reflection
Source
# File lib/sequel/model/associations.rb 3089 def set_one_to_one_associated_object(opts, o) 3090 raise(Error, "object #{inspect} does not have a primary key") unless pk 3091 _set_associated_object(opts, o) 3092 end
Set the given object as the associated object for the given one_to_one association reflection