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