diff options
Diffstat (limited to 'activerecord/lib/active_record/associations/builder')
7 files changed, 75 insertions, 79 deletions
diff --git a/activerecord/lib/active_record/associations/builder/association.rb b/activerecord/lib/active_record/associations/builder/association.rb index 947d61ee7b..88406740d8 100644 --- a/activerecord/lib/active_record/associations/builder/association.rb +++ b/activerecord/lib/active_record/associations/builder/association.rb @@ -1,5 +1,3 @@ -require 'active_support/core_ext/module/attribute_accessors' - # This is the parent Association class which defines the variables # used by all associations. # @@ -15,15 +13,10 @@ module ActiveRecord::Associations::Builder class Association #:nodoc: class << self attr_accessor :extensions - # TODO: This class accessor is needed to make activerecord-deprecated_finders work. - # We can move it to a constant in 5.0. - attr_accessor :valid_options end self.extensions = [] - self.valid_options = [:class_name, :class, :foreign_key, :validate] - - attr_reader :name, :scope, :options + VALID_OPTIONS = [:class_name, :class, :foreign_key, :validate] # :nodoc: def self.build(model, name, scope, options, &block) if model.dangerous_attribute_method?(name) @@ -32,57 +25,60 @@ module ActiveRecord::Associations::Builder "Please choose a different association name." end - builder = create_builder model, name, scope, options, &block - reflection = builder.build(model) + extension = define_extensions model, name, &block + reflection = create_reflection model, name, scope, options, extension define_accessors model, reflection define_callbacks model, reflection define_validations model, reflection - builder.define_extensions model reflection end - def self.create_builder(model, name, scope, options, &block) + def self.create_reflection(model, name, scope, options, extension = nil) raise ArgumentError, "association names must be a Symbol" unless name.kind_of?(Symbol) - new(model, name, scope, options, &block) - end - - def initialize(model, name, scope, options) - # TODO: Move this to create_builder as soon we drop support to activerecord-deprecated_finders. if scope.is_a?(Hash) options = scope scope = nil end - # TODO: Remove this model argument as soon we drop support to activerecord-deprecated_finders. - @name = name - @scope = scope - @options = options + validate_options(options) - validate_options + scope = build_scope(scope, extension) + + ActiveRecord::Reflection.create(macro, name, scope, options, model) + end + + def self.build_scope(scope, extension) + new_scope = scope if scope && scope.arity == 0 - @scope = proc { instance_exec(&scope) } + new_scope = proc { instance_exec(&scope) } + end + + if extension + new_scope = wrap_scope new_scope, extension end + + new_scope end - def build(model) - ActiveRecord::Reflection.create(macro, name, scope, options, model) + def self.wrap_scope(scope, extension) + scope end - def macro + def self.macro raise NotImplementedError end - def valid_options - Association.valid_options + Association.extensions.flat_map(&:valid_options) + def self.valid_options(options) + VALID_OPTIONS + Association.extensions.flat_map(&:valid_options) end - def validate_options - options.assert_valid_keys(valid_options) + def self.validate_options(options) + options.assert_valid_keys(valid_options(options)) end - def define_extensions(model) + def self.define_extensions(model, name) end def self.define_callbacks(model, reflection) @@ -133,8 +129,6 @@ module ActiveRecord::Associations::Builder raise NotImplementedError end - private - def self.check_dependent_options(dependent) unless valid_dependent_options.include? dependent raise ArgumentError, "The :dependent option must be one of #{valid_dependent_options}, but is :#{dependent}" diff --git a/activerecord/lib/active_record/associations/builder/belongs_to.rb b/activerecord/lib/active_record/associations/builder/belongs_to.rb index 954ea3878a..ec135d49b7 100644 --- a/activerecord/lib/active_record/associations/builder/belongs_to.rb +++ b/activerecord/lib/active_record/associations/builder/belongs_to.rb @@ -1,11 +1,11 @@ module ActiveRecord::Associations::Builder class BelongsTo < SingularAssociation #:nodoc: - def macro + def self.macro :belongs_to end - def valid_options - super + [:foreign_type, :polymorphic, :touch, :counter_cache] + def self.valid_options(options) + super + [:foreign_type, :polymorphic, :touch, :counter_cache, :optional] end def self.valid_dependent_options @@ -23,8 +23,6 @@ module ActiveRecord::Associations::Builder add_counter_cache_methods mixin end - private - def self.add_counter_cache_methods(mixin) return if mixin.method_defined? :belongs_to_counter_cache_after_update @@ -112,5 +110,23 @@ module ActiveRecord::Associations::Builder name = reflection.name model.after_destroy lambda { |o| o.association(name).handle_dependency } end + + def self.define_validations(model, reflection) + if reflection.options.key?(:required) + reflection.options[:optional] = !reflection.options.delete(:required) + end + + if reflection.options[:optional].nil? + required = model.belongs_to_required_by_default + else + required = !reflection.options[:optional] + end + + super + + if required + model.validates_presence_of reflection.name, message: :required + end + end end end diff --git a/activerecord/lib/active_record/associations/builder/collection_association.rb b/activerecord/lib/active_record/associations/builder/collection_association.rb index bc15a49996..2ff67f904d 100644 --- a/activerecord/lib/active_record/associations/builder/collection_association.rb +++ b/activerecord/lib/active_record/associations/builder/collection_association.rb @@ -7,22 +7,11 @@ module ActiveRecord::Associations::Builder CALLBACKS = [:before_add, :after_add, :before_remove, :after_remove] - def valid_options + def self.valid_options(options) super + [:table_name, :before_add, :after_add, :before_remove, :after_remove, :extend] end - attr_reader :block_extension - - def initialize(model, name, scope, options) - super - @mod = nil - if block_given? - @mod = Module.new(&Proc.new) - @scope = wrap_scope @scope, @mod - end - end - def self.define_callbacks(model, reflection) super name = reflection.name @@ -32,10 +21,11 @@ module ActiveRecord::Associations::Builder } end - def define_extensions(model) - if @mod + def self.define_extensions(model, name) + if block_given? extension_module_name = "#{model.name.demodulize}#{name.to_s.camelize}AssociationExtension" - model.parent.const_set(extension_module_name, @mod) + extension = Module.new(&Proc.new) + model.parent.const_set(extension_module_name, extension) end end @@ -78,9 +68,7 @@ module ActiveRecord::Associations::Builder CODE end - private - - def wrap_scope(scope, mod) + def self.wrap_scope(scope, mod) if scope proc { |owner| instance_exec(owner, &scope).extending(mod) } else diff --git a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb index 815e8eb97f..93dc4ae118 100644 --- a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb +++ b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb @@ -87,18 +87,18 @@ module ActiveRecord::Associations::Builder middle_name = [lhs_model.name.downcase.pluralize, association_name].join('_').gsub(/::/, '_').to_sym middle_options = middle_options join_model - hm_builder = HasMany.create_builder(lhs_model, - middle_name, - nil, - middle_options) - hm_builder.build lhs_model + + HasMany.create_reflection(lhs_model, + middle_name, + nil, + middle_options) end private def middle_options(join_model) middle_options = {} - middle_options[:class] = join_model + middle_options[:class_name] = "#{lhs_model.name}::#{join_model.name}" middle_options[:source] = join_model.left_reflection.name if options.key? :foreign_key middle_options[:foreign_key] = options[:foreign_key] @@ -110,7 +110,7 @@ module ActiveRecord::Associations::Builder rhs_options = {} if options.key? :class_name - rhs_options[:foreign_key] = options[:class_name].foreign_key + rhs_options[:foreign_key] = options[:class_name].to_s.foreign_key rhs_options[:class_name] = options[:class_name] end diff --git a/activerecord/lib/active_record/associations/builder/has_many.rb b/activerecord/lib/active_record/associations/builder/has_many.rb index 4c8c826f76..1c1b47bd56 100644 --- a/activerecord/lib/active_record/associations/builder/has_many.rb +++ b/activerecord/lib/active_record/associations/builder/has_many.rb @@ -1,11 +1,11 @@ module ActiveRecord::Associations::Builder class HasMany < CollectionAssociation #:nodoc: - def macro + def self.macro :has_many end - def valid_options - super + [:primary_key, :dependent, :as, :through, :source, :source_type, :inverse_of, :counter_cache, :join_table] + def self.valid_options(options) + super + [:primary_key, :dependent, :as, :through, :source, :source_type, :inverse_of, :counter_cache, :join_table, :foreign_type] end def self.valid_dependent_options diff --git a/activerecord/lib/active_record/associations/builder/has_one.rb b/activerecord/lib/active_record/associations/builder/has_one.rb index c194c8ae9a..a272d3c781 100644 --- a/activerecord/lib/active_record/associations/builder/has_one.rb +++ b/activerecord/lib/active_record/associations/builder/has_one.rb @@ -1,11 +1,11 @@ module ActiveRecord::Associations::Builder class HasOne < SingularAssociation #:nodoc: - def macro + def self.macro :has_one end - def valid_options - valid = super + [:as] + def self.valid_options(options) + valid = super + [:as, :foreign_type] valid += [:through, :source, :source_type] if options[:through] valid end @@ -14,10 +14,15 @@ module ActiveRecord::Associations::Builder [:destroy, :delete, :nullify, :restrict_with_error, :restrict_with_exception] end - private - def self.add_destroy_callbacks(model, reflection) super unless reflection.options[:through] end + + def self.define_validations(model, reflection) + super + if reflection.options[:required] + model.validates_presence_of reflection.name, message: :required + end + end end end diff --git a/activerecord/lib/active_record/associations/builder/singular_association.rb b/activerecord/lib/active_record/associations/builder/singular_association.rb index 6e6dd7204c..42542f188e 100644 --- a/activerecord/lib/active_record/associations/builder/singular_association.rb +++ b/activerecord/lib/active_record/associations/builder/singular_association.rb @@ -2,7 +2,7 @@ module ActiveRecord::Associations::Builder class SingularAssociation < Association #:nodoc: - def valid_options + def self.valid_options(options) super + [:dependent, :primary_key, :inverse_of, :required] end @@ -27,12 +27,5 @@ module ActiveRecord::Associations::Builder end CODE end - - def self.define_validations(model, reflection) - super - if reflection.options[:required] - model.validates_presence_of reflection.name - end - end end end |