Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 122 lines (98 sloc) 3.116 kB
7f24d3d @vijaydev copy edits[ci skip]
vijaydev authored
1 # This is the parent Association class which defines the variables
2 # used by all associations.
3 #
4 # The hierarchy is defined as follows:
3a4d0b1 @carlosantoniodasilva Refactor to use flat_map
carlosantoniodasilva authored
5 # Association
da8fff5 @aditya-kapoor Added some more documentation for ActiveRecord::Associations::Builder…
aditya-kapoor authored
6 # - SingularAssociation
7f24d3d @vijaydev copy edits[ci skip]
vijaydev authored
7 # - BelongsToAssociation
8 # - HasOneAssociation
da8fff5 @aditya-kapoor Added some more documentation for ActiveRecord::Associations::Builder…
aditya-kapoor authored
9 # - CollectionAssociation
7f24d3d @vijaydev copy edits[ci skip]
vijaydev authored
10 # - HasManyAssociation
11 # - HasAndBelongsToManyAssociation
0fbf31b @aditya-kapoor Added documentation for ActiveRecord::Associations::Builder::Associat…
aditya-kapoor authored
12
52f8e4b @jonleighton Use proper objects to do the work to build the associations (adding m…
jonleighton authored
13 module ActiveRecord::Associations::Builder
14 class Association #:nodoc:
09d2f16 @jonleighton stop using class_attribute where methods/inheritance will suffice.
jonleighton authored
15 class << self
7085aae @tenderlove extend by adding relationships rather than monkey patching
tenderlove authored
16 attr_accessor :extensions
09d2f16 @jonleighton stop using class_attribute where methods/inheritance will suffice.
jonleighton authored
17 end
f7f422f @tenderlove remove `valid_options` class method
tenderlove authored
18 self.extensions = []
52f8e4b @jonleighton Use proper objects to do the work to build the associations (adding m…
jonleighton authored
19
1f006cd @tenderlove support anonymous classes on has_many associations
tenderlove authored
20 VALID_OPTIONS = [:class_name, :class, :foreign_key, :validate]
52f8e4b @jonleighton Use proper objects to do the work to build the associations (adding m…
jonleighton authored
21
d80a5cc @tenderlove association builder classes no longer need the model
tenderlove authored
22 attr_reader :name, :scope, :options
52f8e4b @jonleighton Use proper objects to do the work to build the associations (adding m…
jonleighton authored
23
a9087ab @tenderlove push some validation up to the factory method
tenderlove authored
24 def self.build(model, name, scope, options, &block)
25 raise ArgumentError, "association names must be a Symbol" unless name.kind_of?(Symbol)
26
5b527dc @tenderlove push option handling "chrome" outside `initialize`
tenderlove authored
27 if scope.is_a?(Hash)
28 options = scope
29 scope = nil
30 end
31
d80a5cc @tenderlove association builder classes no longer need the model
tenderlove authored
32 builder = new(name, scope, options, &block)
33 reflection = builder.build(model)
faf4a39 @tenderlove make mutation method apis more consistent
tenderlove authored
34 builder.define_accessors model
537fe2b @tenderlove remove dependency on @model when defining callbacks
tenderlove authored
35 builder.define_callbacks model, reflection
86588f9 @tenderlove push more mutations outside the factory method
tenderlove authored
36 builder.define_extensions model
49d50b9 @tenderlove extract more mutations to the caller
tenderlove authored
37 reflection
52f8e4b @jonleighton Use proper objects to do the work to build the associations (adding m…
jonleighton authored
38 end
39
d80a5cc @tenderlove association builder classes no longer need the model
tenderlove authored
40 def initialize(name, scope, options)
5a54bff @jonleighton Allow associations to take a lambda which builds the scope
jonleighton authored
41 @name = name
5b527dc @tenderlove push option handling "chrome" outside `initialize`
tenderlove authored
42 @scope = scope
43 @options = options
7fa9cb5 @jonleighton fix association :extend option
jonleighton authored
44
bc06ee3 @tenderlove we should not allow invalid objects to be constructed
tenderlove authored
45 validate_options
46
4b87854 @tenderlove remove intermediate assignments
tenderlove authored
47 if scope && scope.arity == 0
48 @scope = proc { instance_exec(&scope) }
7fa9cb5 @jonleighton fix association :extend option
jonleighton authored
49 end
61bcc31 @joshsusser use GeneratedFeatureMethods module for associations
joshsusser authored
50 end
51
d80a5cc @tenderlove association builder classes no longer need the model
tenderlove authored
52 def build(model)
49d50b9 @tenderlove extract more mutations to the caller
tenderlove authored
53 ActiveRecord::Reflection.create(macro, name, scope, options, model)
09d2f16 @jonleighton stop using class_attribute where methods/inheritance will suffice.
jonleighton authored
54 end
55
56 def macro
57 raise NotImplementedError
58 end
59
60 def valid_options
f7f422f @tenderlove remove `valid_options` class method
tenderlove authored
61 VALID_OPTIONS + Association.extensions.flat_map(&:valid_options)
52f8e4b @jonleighton Use proper objects to do the work to build the associations (adding m…
jonleighton authored
62 end
63
825c05d @jonleighton Unprivatise all the things
jonleighton authored
64 def validate_options
65 options.assert_valid_keys(valid_options)
66 end
7085aae @tenderlove extend by adding relationships rather than monkey patching
tenderlove authored
67
86588f9 @tenderlove push more mutations outside the factory method
tenderlove authored
68 def define_extensions(model)
69 end
70
537fe2b @tenderlove remove dependency on @model when defining callbacks
tenderlove authored
71 def define_callbacks(model, reflection)
9da52a5 @tenderlove push more mutations out of the builder
tenderlove authored
72 add_before_destroy_callbacks(model, name) if options[:dependent]
49d50b9 @tenderlove extract more mutations to the caller
tenderlove authored
73 Association.extensions.each do |extension|
537fe2b @tenderlove remove dependency on @model when defining callbacks
tenderlove authored
74 extension.build model, reflection
49d50b9 @tenderlove extract more mutations to the caller
tenderlove authored
75 end
76 end
77
90e60aa @aditya-kapoor Added some more documentation for define_readers and define_writer of…
aditya-kapoor authored
78 # Defines the setter and getter methods for the association
79 # class Post < ActiveRecord::Base
80 # has_many :comments
81 # end
3a4d0b1 @carlosantoniodasilva Refactor to use flat_map
carlosantoniodasilva authored
82 #
90e60aa @aditya-kapoor Added some more documentation for define_readers and define_writer of…
aditya-kapoor authored
83 # Post.first.comments and Post.first.comments= methods are defined by this method...
52f8e4b @jonleighton Use proper objects to do the work to build the associations (adding m…
jonleighton authored
84
faf4a39 @tenderlove make mutation method apis more consistent
tenderlove authored
85 def define_accessors(model)
86 mixin = model.generated_feature_methods
c856d89 @tenderlove pass the mixin in to the code generation methods
tenderlove authored
87 define_readers(mixin)
88 define_writers(mixin)
825c05d @jonleighton Unprivatise all the things
jonleighton authored
89 end
52f8e4b @jonleighton Use proper objects to do the work to build the associations (adding m…
jonleighton authored
90
c856d89 @tenderlove pass the mixin in to the code generation methods
tenderlove authored
91 def define_readers(mixin)
6e57d5c @jonleighton Use method compilation for association methods
jonleighton authored
92 mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
93 def #{name}(*args)
94 association(:#{name}).reader(*args)
95 end
96 CODE
825c05d @jonleighton Unprivatise all the things
jonleighton authored
97 end
52f8e4b @jonleighton Use proper objects to do the work to build the associations (adding m…
jonleighton authored
98
c856d89 @tenderlove pass the mixin in to the code generation methods
tenderlove authored
99 def define_writers(mixin)
6e57d5c @jonleighton Use method compilation for association methods
jonleighton authored
100 mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
101 def #{name}=(value)
102 association(:#{name}).writer(value)
103 end
104 CODE
825c05d @jonleighton Unprivatise all the things
jonleighton authored
105 end
52f8e4b @jonleighton Use proper objects to do the work to build the associations (adding m…
jonleighton authored
106
9da52a5 @tenderlove push more mutations out of the builder
tenderlove authored
107 def valid_dependent_options
108 raise NotImplementedError
109 end
110
111 private
112
113 def add_before_destroy_callbacks(model, name)
6bb8afb @jonleighton DRY up handling of dependent option
jonleighton authored
114 unless valid_dependent_options.include? options[:dependent]
115 raise ArgumentError, "The :dependent option must be one of #{valid_dependent_options}, but is :#{options[:dependent]}"
52f8e4b @jonleighton Use proper objects to do the work to build the associations (adding m…
jonleighton authored
116 end
336ff8a @hindenbug has_many/has_one, :dependent => :restrict, deprecation added.
hindenbug authored
117
9da52a5 @tenderlove push more mutations out of the builder
tenderlove authored
118 model.before_destroy lambda { |o| o.association(name).handle_dependency }
825c05d @jonleighton Unprivatise all the things
jonleighton authored
119 end
ae3b015 @arunagw warning removed: mismatched indentations
arunagw authored
120 end
52f8e4b @jonleighton Use proper objects to do the work to build the associations (adding m…
jonleighton authored
121 end
Something went wrong with that request. Please try again.