association.rb 2.7 KB
Newer Older
1 2 3
module ActiveRecord::Associations::Builder
  class Association #:nodoc:
    class_attribute :valid_options
4
    self.valid_options = [:class_name, :foreign_key, :select, :conditions, :include, :extend, :readonly, :validate, :references]
5 6 7 8

    # Set by subclasses
    class_attribute :macro

9
    attr_reader :model, :name, :scope, :options, :reflection
10

11 12
    def self.build(*args, &block)
      new(*args, &block).build
13 14
    end

15 16 17 18 19 20 21 22 23 24 25
    def initialize(model, name, scope, options)
      @model   = model
      @name    = name

      if options
        @scope   = scope
        @options = options
      else
        @scope   = nil
        @options = scope
      end
26 27 28 29
    end

    def mixin
      @model.generated_feature_methods
30 31 32 33
    end

    def build
      validate_options
34
      reflection = model.create_reflection(self.class.macro, name, scope, options, model)
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
      define_accessors
      reflection
    end

    private

      def validate_options
        options.assert_valid_keys(self.class.valid_options)
      end

      def define_accessors
        define_readers
        define_writers
      end

      def define_readers
        name = self.name
J
Josh Susser 已提交
52
        mixin.redefine_method(name) do |*params|
53 54 55 56 57 58
          association(name).reader(*params)
        end
      end

      def define_writers
        name = self.name
J
Josh Susser 已提交
59
        mixin.redefine_method("#{name}=") do |value|
60 61 62
          association(name).writer(value)
        end
      end
63 64 65 66 67 68 69

      def dependent_restrict_raises?
        ActiveRecord::Base.dependent_restrict_raises == true
      end

      def dependent_restrict_deprecation_warning
        if dependent_restrict_raises?
70 71 72
          msg = "In the next release, `:dependent => :restrict` will not raise a `DeleteRestrictionError`. "\
                "Instead, it will add an error on the model. To fix this warning, make sure your code " \
                "isn't relying on a `DeleteRestrictionError` and then add " \
73 74 75 76
                "`config.active_record.dependent_restrict_raises = false` to your application config."
          ActiveSupport::Deprecation.warn msg
        end
      end
77 78 79 80

      def define_restrict_dependency_method
        name = self.name
        mixin.redefine_method(dependency_method_name) do
81 82
          has_one_macro = association(name).reflection.macro == :has_one
          if has_one_macro ? !send(name).nil? : send(name).exists?
83 84 85
            if dependent_restrict_raises?
              raise ActiveRecord::DeleteRestrictionError.new(name)
            else
86
              key  = has_one_macro ? "one" : "many"
87 88
              errors.add(:base, :"restrict_dependent_destroy.#{key}",
                         :record => self.class.human_attribute_name(name).downcase)
89 90 91 92 93
              return false
            end
          end
        end
      end
94
  end
95
end