custom_fields 1.0.0.beta.25 → 1.1.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.textile CHANGED
@@ -1,16 +1,59 @@
1
1
  h1. CustomFields
2
2
 
3
3
  Manage custom fields to a mongoid document or a collection. This module is one of the core features we implemented in our custom cms named Locomotive.
4
+ Basically, its aim is to provide to editors a way to manage extra fields to a Mongoid document through for instance a web UI.
5
+
6
+ The main goals:
7
+
8
+ * offering a very secure way to add / edit / delete extra fields to a Mongoid document
9
+ * scoping the modifications added to a Mongoid document so that other documents of the same class won't be updated.
4
10
 
5
11
  h2. Requirements
6
12
 
7
- ActiveSupport 3.0.7, MongoDB 1.6 and Mongoid 2.0.2
13
+ ActiveSupport 3.1.1, MongoDB 2.0 and Mongoid 2.3.2
14
+
15
+ h2. Examples
16
+
17
+ h3. On a has_many relationship
18
+
19
+ bc.. class Company
20
+ embeds_many :employees
21
+
22
+ custom_fields_for :employees
23
+ end
24
+
25
+ class Employee
26
+ field :name, String
27
+
28
+ embedded_in :company, :inverse_of => :employees
29
+ end
30
+
31
+ company = Company.new
32
+ company.employees_custom_fields.build :label => 'His/her position', :_alias => 'position', :kind => 'string', :required => true
33
+
34
+ company.save
35
+
36
+ company.employees.build :name => 'Michael Scott', :position => 'Regional manager'
37
+
38
+ another_company = Company.new
39
+ employee = company.employees.build
40
+ employee.position # returns a "not defined method" error
41
+
42
+ h3. On the class itself
43
+
44
+ bc.. class Company
45
+ custom_fields_for_itself
46
+ end
8
47
 
48
+ company = Company.new
49
+ company.self_metadata_custom_fields.build :label => 'Shipping Address', :_alias => 'address', :kind => 'text'
9
50
 
10
- h2. Example
51
+ company.save
11
52
 
12
- Coming soon but take a look of the tests to see what CustomFields is capable of.
53
+ company.self_metadata.address = '700 S Laflin, 60607 Chicago'
13
54
 
55
+ another_company = Company.new
56
+ other_company.self_metadata.address # returns a "not defined method" error
14
57
 
15
58
  h2. Contact
16
59
 
@@ -12,175 +12,329 @@ module CustomFields
12
12
 
13
13
  module InstanceMethods
14
14
 
15
- def custom_fields_for?(collection_name)
16
- self.class.custom_fields_for?(collection_name)
15
+ # Determines if the relation is enhanced by the custom fields
16
+ #
17
+ # @example the Person class has somewhere in its code this: "custom_fields_for :addresses"
18
+ # person.custom_fields_for?(:addresses)
19
+ #
20
+ # @param [ String, Symbol ] name The name of the relation.
21
+ #
22
+ # @return [ true, false ] True if enhanced, false if not.
23
+ #
24
+ def custom_fields_for?(name)
25
+ self.class.custom_fields_for?(name)
17
26
  end
18
27
 
28
+ # Returns the class enhanced by the custom fields defined in the parent class.
29
+ #
30
+ # @param [ String, Symbol ] name The name of the relation.
31
+ #
32
+ # @return [ Class ] The modified class.
33
+ #
34
+ def klass_with_custom_fields(name)
35
+ self.class.klass_with_custom_fields(name, self)
36
+ end
37
+
38
+ # Returns the ordered list of custom fields for a relation
39
+ #
40
+ # @example the Person class has somewhere in its code this: "custom_fields_for :addresses"
41
+ # person.ordered_custom_fields(:addresses)
42
+ #
43
+ # @param [ String, Symbol ] name The name of the relation.
44
+ #
45
+ # @return [ Collection ] The ordered list.
46
+ #
47
+ def ordered_custom_fields(name)
48
+ self.send(:"#{name}_custom_fields").sort { |a, b| (a.position || 0) <=> (b.position || 0) }
49
+ end
50
+
51
+ # Marks all the custom fields as persisted. Actually, this is a patch
52
+ # for mongoid since for the update, it runs the reset_persisted_children method after
53
+ # the callbacks unlike for the create.
54
+ # We assume that all the fields have been validated in a previous step
55
+ #
56
+ # @param [ String, Symbol ] name The name of the relation.
57
+ #
58
+ def mark_custom_fields_as_persisted(name)
59
+ self.send(:"#{name}_custom_fields").each do |field|
60
+ field.instance_variable_set(:@new_record, false) unless field.persisted?
61
+ end
62
+ end
63
+
64
+ # Builds the class enhanced by the custom fields defined in the parent class.
65
+ # The new class inherits from the original one.
66
+ #
67
+ # @param [ String, Symbol ] name The name of the relation.
68
+ # @param [ Metadata ] metadata The relation's metadata.
69
+ #
70
+ # @return [ Class ] The modified class.
71
+ #
72
+ def build_klass_with_custom_fields(name, metadata)
73
+ custom_fields = self.ordered_custom_fields(name)
74
+
75
+ metadata.klass.to_klass_with_custom_fields(name, self, custom_fields)
76
+ end
77
+
78
+ # Marks the class enhanced by the custom fields as invalidated
79
+ #
80
+ # @param [ String, Symbol ] name The name of the relation.
81
+ #
82
+ def mark_klass_with_custom_fields_as_invalidated(name)
83
+ self.send(:"invalidate_#{name}_klass_flag=", true)
84
+ end
85
+
86
+ # Reset the flag telling if the class enhanced by the custom fields is invalidated
87
+ #
88
+ # @param [ String, Symbol ] name The name of the relation.
89
+ #
90
+ def reset_klass_with_custom_fields_invalidated_flag(name)
91
+ # puts "* reset_klass_with_custom_fields_invalidated_flag #{name}"
92
+ self.send(:"invalidate_#{name}_klass_flag=", false)
93
+ end
94
+
95
+ # Determines if the enhanced class has to be invalidated.
96
+ #
97
+ # @param [ String, Symbol ] name The name of the relation.
98
+ #
99
+ # @return [ true, false ] True if enhanced, false if not.
100
+ #
101
+ def invalidate_klass_with_custom_fields?(name)
102
+ !!self.send(:"invalidate_#{name}_klass_flag")
103
+ end
104
+
105
+ # Destroy the class enhanced by the custom fields so that next time we need it,
106
+ # we have a fresh new one.
107
+ #
108
+ # @param [ String, Symbol ] name The name of the relation.
109
+ #
110
+ def invalidate_klass_with_custom_fields(name)
111
+ self.class.invalidate_klass_with_custom_fields(name, self)
112
+ end
113
+
114
+ # Duplicates a metadata and assigns the enhanced class to it.
115
+ #
116
+ # @param [ Metadata ] metadata The relation's old metadata.
117
+ #
118
+ # @return [ Metadata ] The relation's new metadata
119
+ #
19
120
  def clone_metadata_for_custom_fields(metadata)
20
- singular_name = metadata.name.to_s.singularize.gsub(/^_/, '')
121
+ # puts "-> clone_metadata_for_custom_fields #{metadata.name}"
21
122
 
22
- klass = self.send(:"fetch_#{singular_name}_klass")
123
+ klass = self.build_klass_with_custom_fields(metadata.name, metadata)
23
124
 
24
- # safer to do that because we are going to modify the metadata klass for next operations
125
+ # we do not want that other instances of the parent class have the same metadata
25
126
  metadata.clone.tap do |metadata|
26
127
  metadata.instance_variable_set(:@klass, klass)
27
128
  end
28
129
  end
29
130
 
30
- end
131
+ # When the fields have been modified and before the object is saved,
132
+ # we bump the version.
133
+ #
134
+ # @param [ String, Symbol ] name The name of the relation.
135
+ #
136
+ def bump_custom_fields_version(name)
137
+ if self.invalidate_klass_with_custom_fields?(name)
138
+ # puts "%%% bump_custom_fields_version #{name} #{self.send(:"#{name}_custom_fields_version").inspect}"
139
+ version = self.send(:"#{name}_custom_fields_version") || 0
140
+ self.send(:"#{name}_custom_fields_version=", version + 1)
141
+ end
142
+ end
31
143
 
32
- # Enhance an embedded collection OR the instance itself (by passing self) by providing methods to manage custom fields.
33
- #
34
- # class Company
35
- #
36
- # custom_fields_for :self
37
- #
38
- # embeds_many :employees
39
- # custom_fields_for :employees
40
- # end
41
- #
42
- # class Employee
43
- # embedded_in :company, :inverse_of => :employees
44
- # field :name, String
45
- # end
46
- #
47
- # company.employee_custom_fields.build :label => 'His/her position', :_alias => 'position', :kind => 'string'
48
- #
49
- # company.employees.build :name => 'Michael Scott', :position => 'Regional manager'
50
- #
51
- #
52
- # company.self_custom_fields.build :label => 'Shipping Address', :_alias => 'address', :kind => 'text'
53
- #
54
- # company.metadata.address = '700 S Laflin, 60607 Chicago'
55
- #
56
- # other_company.metadata.address # returns a "not defined method" error
57
- #
58
- module ClassMethods
144
+ # Increments by 1 the counter couting the number of added custom fields
145
+ # for a relation
146
+ #
147
+ # @param [ String, Symbol ] name The name of the relation.
148
+ #
149
+ # @return [ Integer ] The new value of the counter
150
+ #
151
+ def bump_custom_fields_counter(name)
152
+ counter = self.send(:"#{name}_custom_fields_counter") || 0
153
+ self.send(:"#{name}_custom_fields_counter=", counter + 1)
154
+ end
155
+
156
+ # Builds a new relation so that the builder takes the last version of
157
+ # the enhanced class when creating new instances
158
+ #
159
+ # @param [ String, Symbol ] name The name of the relation.
160
+ #
161
+ def rebuild_custom_fields_relation(name)
162
+ # metadata = self.clone_metadata_for_custom_fields(self.relations[name.to_s])
163
+
164
+ # puts "rebuild_custom_fields_relation #{name}"
59
165
 
60
- def custom_fields_for?(collection_name)
61
- self._custom_fields_for.include?(collection_name.to_s)
166
+ metadata = self.relations[name.to_s]
167
+ self.build(name, nil, metadata)
62
168
  end
63
169
 
64
- def custom_fields_for(collection_name)
65
- singular_name = collection_name.to_s.singularize
66
- dynamic_custom_field_class_name = "#{self.name}#{singular_name.camelize}Field"
170
+ end
67
171
 
68
- self.declare_embedded_in_definition_in_custom_field(collection_name)
172
+ module ClassMethods
69
173
 
70
- # enhance the class itself
71
- if (itself = %w(itself self).include?(collection_name.to_s))
72
- collection_name, singular_name = '_metadata', 'metadata'
174
+ # Determines if the relation is enhanced by the custom fields
175
+ #
176
+ # @example the Person class has somewhere in its code this: "custom_fields_for :addresses"
177
+ # Person.custom_fields_for?(:addresses)
178
+ #
179
+ # @param [ String, Symbol ] name The name of the relation.
180
+ #
181
+ # @return [ true, false ] True if enhanced, false if not.
182
+ #
183
+ def custom_fields_for?(name)
184
+ self._custom_fields_for.include?(name.to_s)
185
+ end
73
186
 
74
- class_eval <<-EOV
75
- embeds_one :#{collection_name}, :class_name => '::CustomFields::Metadata'
187
+ # Enhance an embedded collection OR the instance itself (by passing self) by providing methods to manage custom fields.
188
+ #
189
+ # @param [ String, Symbol ] name The name of the relation.
190
+ #
191
+ # @example
192
+ # class Company
193
+ # embeds_many :employees
194
+ # custom_fields_for :employees
195
+ # end
196
+ #
197
+ # class Employee
198
+ # embedded_in :company, :inverse_of => :employees
199
+ # field :name, String
200
+ # end
201
+ #
202
+ # company.employees_custom_fields.build :label => 'His/her position', :_alias => 'position', :kind => 'string'
203
+ # company.employees.build :name => 'Michael Scott', :position => 'Regional manager'
204
+ #
205
+ def custom_fields_for(name)
206
+ self.declare_embedded_in_definition_in_custom_field(name)
207
+
208
+ # stores the relation name
209
+ self._custom_fields_for << name.to_s
210
+
211
+ self.extend_for_custom_fields(name)
212
+ end
76
213
 
77
- def safe_#{singular_name}
78
- self.#{collection_name} || self.build_#{collection_name}
79
- end
80
- EOV
214
+ # Enhances the class itself
215
+ #
216
+ # @example
217
+ # class Company
218
+ # custom_fields_for_itself
219
+ # end
220
+ #
221
+ # company.self_metadata_custom_fields.build :label => 'Shipping Address', :_alias => 'address', :kind => 'text'
222
+ # company.self_metadata.address = '700 S Laflin, 60607 Chicago'
223
+ # other_company.self_metadata.address # returns a "not defined method" error
224
+ #
225
+ def custom_fields_for_itself
226
+ self.embeds_one :self_metadata, :class_name => '::CustomFields::SelfMetadata'
227
+
228
+ class_eval do
229
+ def self_metadata_with_automatic_build
230
+ object = self_metadata_without_automatic_build
231
+ object || self.build_self_metadata
232
+ end
233
+ alias_method_chain :self_metadata, :automatic_build
81
234
  end
82
235
 
83
- # record the collection_name
84
- self._custom_fields_for << collection_name.to_s
236
+ self.custom_fields_for('self_metadata')
237
+ end
85
238
 
86
- # common part
87
- class_eval <<-EOV
88
- field :#{singular_name}_custom_fields_counter, :type => Integer, :default => 0
89
- field :#{singular_name}_custom_fields_version, :type => Integer, :default => 0
90
-
91
- embeds_many :#{singular_name}_custom_fields, :class_name => '#{dynamic_custom_field_class_name}' do
92
- def build(attributes = {}, type = nil, &block)
93
- instantiated(type).tap do |doc|
94
- append(doc, default_options(:binding => true))
95
- doc.write_attributes(attributes)
96
- doc.identify
97
- block.call(doc) if block
98
- end
99
- end
100
- alias :new :build
101
- end
239
+ protected
102
240
 
103
- attr_accessor :invalidate_#{singular_name}_klass_flag
241
+ # Extends / Decorates the current class in order to be fully custom_fields compliant.
242
+ # it declares news fields, adds new callbacks, ...etc
243
+ #
244
+ # @param [ String, Symbol ] name The name of the relation.
245
+ #
246
+ def extend_for_custom_fields(name)
247
+ class_eval do
248
+ field :"#{name}_custom_fields_counter", :type => Integer, :default => 0
249
+ field :"#{name}_custom_fields_version", :type => Integer, :default => 0
104
250
 
105
- before_save do |record|
106
- if record.invalidate_#{singular_name}_klass?
107
- record.#{singular_name}_custom_fields_version ||= 0
108
- record.#{singular_name}_custom_fields_version += 1
109
- # puts "[parent/before_save] set #{singular_name}_custom_fields_version " + record.#{singular_name}_custom_fields_version.to_s # debug purpose
110
- end
111
- end
251
+ embeds_many :"#{name}_custom_fields", :class_name => self.dynamic_custom_field_class_name(name), :cascade_callbacks => true
112
252
 
113
- after_destroy :invalidate_#{singular_name}_klass
253
+ attr_accessor :"invalidate_#{name}_klass_flag" # flag for invalidating the custom class
114
254
 
115
- accepts_nested_attributes_for :#{singular_name}_custom_fields, :allow_destroy => true
255
+ accepts_nested_attributes_for :"#{name}_custom_fields", :allow_destroy => true
256
+ end
116
257
 
117
- def ordered_#{singular_name}_custom_fields
118
- self.#{singular_name}_custom_fields.sort { |a, b| (a.position || 0) <=> (b.position || 0) }
119
- end
258
+ class_eval <<-EOV
120
259
 
121
- def fetch_#{singular_name}_klass
122
- metadata = self.relations['#{collection_name.to_s}']
123
- metadata.klass.to_klass_with_custom_fields(self.ordered_#{singular_name}_custom_fields, self, metadata.name)
124
- end
260
+ before_save :bump_#{name}_custom_fields_version
261
+ after_save :mark_#{name}_custom_fields_as_persisted
262
+ after_save :rebuild_#{name}_relation
263
+ after_save :reset_#{name}_klass_invalidated_flag
264
+ after_destroy :invalidate_#{name}_klass
125
265
 
126
- def #{singular_name}_klass
127
- metadata = self.relations['#{collection_name.to_s}']
128
- metadata.klass.current_klass_with_custom_fields(self, metadata.name)
266
+ def #{name}_klass
267
+ self.klass_with_custom_fields('#{name}')
129
268
  end
130
269
 
131
- def #{singular_name}_klass_out_of_date?
132
- self.#{singular_name}_klass.nil? || self.#{singular_name}_klass.version != self.#{singular_name}_custom_fields_version
270
+ def #{name}_klass_name
271
+ self.class.klass_name_with_custom_fields('#{name}', self)
133
272
  end
134
273
 
135
- def invalidate_#{singular_name}_klass
136
- metadata = self.relations['#{collection_name.to_s}']
137
- metadata.klass.invalidate_proxy_class_with_custom_fields(self, metadata.name)
274
+ def #{name}_klass_out_of_date?
275
+ self.#{name}_klass.nil? || self.#{name}_klass.version != self.#{name}_custom_fields_version
138
276
  end
139
277
 
140
- def invalidate_#{singular_name}_klass?
141
- self.invalidate_#{singular_name}_klass_flag == true
278
+ def invalidate_#{name}_klass
279
+ self.invalidate_klass_with_custom_fields('#{name}')
142
280
  end
143
- EOV
144
281
 
145
- # mongoid tiny patch: for performance optimization (ie: we do want to invalidate klass with custom fields every time we save a field)
146
- unless instance_methods.collect(&:to_s).include?('write_attributes_with_custom_fields')
282
+ def invalidate_#{name}_klass?
283
+ self.invalidate_klass_with_custom_fields?('#{name}')
284
+ end
147
285
 
148
- class_eval do
149
- def write_attributes_with_custom_fields(attrs = nil, guard_protected_attributes = true)
150
- self.instance_variable_set(:@_writing_attributes_with_custom_fields, true)
151
- self.write_attributes_without_custom_fields(attrs, guard_protected_attributes)
286
+ def rebuild_#{name}_relation
287
+ # puts "--> AFTER SAVE (#{name})"
288
+ if self.#{name}_klass_out_of_date?
289
+ # puts 'rebuild relation for #{name} after save'
290
+ self.rebuild_custom_fields_relation('#{name}')
152
291
  end
292
+ end
293
+
294
+ protected
153
295
 
154
- alias_method_chain :write_attributes, :custom_fields
296
+ def bump_#{name}_custom_fields_version
297
+ # puts "--> BEFORE SAVE (#{name})"
298
+ self.bump_custom_fields_version('#{name}')
155
299
  end
156
300
 
157
- end
301
+ def mark_#{name}_custom_fields_as_persisted
302
+ self.mark_custom_fields_as_persisted('#{name}')
303
+ end
158
304
 
159
- if itself
160
- class_eval <<-EOV
161
- alias :self_custom_fields :#{singular_name}_custom_fields
162
- EOV
163
- end
305
+ def reset_#{name}_klass_invalidated_flag
306
+ self.reset_klass_with_custom_fields_invalidated_flag('#{name}')
307
+ end
164
308
 
309
+ EOV
165
310
  end
166
311
 
167
- protected
168
-
169
- def dynamic_custom_field_class_name(collection_name)
170
- "#{self.name}#{collection_name.to_s.singularize.camelize}Field"
312
+ # Returns the class name of the custom field which is based both on the parent class name
313
+ # and the name of the relation in order to avoid name conflicts (with other classes)
314
+ #
315
+ # @param [ Metadata ] metadata The relation's old metadata.
316
+ #
317
+ # @return [ String ] The class name
318
+ #
319
+ def dynamic_custom_field_class_name(name)
320
+ "#{self.name}#{name.to_s.singularize.camelize}Field"
171
321
  end
172
322
 
173
323
  # An embedded relationship has to be defined on both side in order for it
174
324
  # to work properly. But because custom_field can be embedded in different
175
325
  # models that it's not aware of, we have to declare manually the definition
176
326
  # once we know the target class.
177
- def declare_embedded_in_definition_in_custom_field(target_collection_name)
178
- singular_name = target_collection_name.to_s.singularize
179
- klass_name = self.dynamic_custom_field_class_name(target_collection_name)
327
+ #
328
+ # @param [ String, Symbol ] name The name of the relation.
329
+ #
330
+ # @return [ Field ] The new field class.
331
+ #
332
+ def declare_embedded_in_definition_in_custom_field(name)
333
+ klass_name = self.dynamic_custom_field_class_name(name)
180
334
 
181
335
  unless Object.const_defined?(klass_name)
182
336
  (klass = Class.new(::CustomFields::Field)).class_eval <<-EOF
183
- embedded_in :#{self.name.underscore}, :inverse_of => :#{singular_name}_custom_fields
337
+ embedded_in :#{self.name.underscore}, :inverse_of => :#{name}_custom_fields
184
338
  EOF
185
339
 
186
340
  Object.const_set(klass_name, klass)
@@ -191,4 +345,6 @@ module CustomFields
191
345
 
192
346
  end
193
347
 
194
- end
348
+ end
349
+
350
+
@@ -0,0 +1,12 @@
1
+ unless ActiveSupport::Callbacks::ClassMethods.method_defined?(:without_callback)
2
+
3
+ module ActiveSupport::Callbacks::ClassMethods
4
+ def without_callback(*args, &block)
5
+ skip_callback(*args)
6
+ yield.tap do |result|
7
+ set_callback(*args)
8
+ end
9
+ end
10
+ end
11
+
12
+ end
@@ -1,9 +1,37 @@
1
1
  # encoding: utf-8
2
2
  module Mongoid #:nodoc:
3
3
 
4
+ # # This is the base module for all domain objects that need to be persisted to
5
+ # # the database as documents.
6
+ # module Document
7
+ #
8
+ # # Reloads the +Document+ attributes from the database. If the document has
9
+ # # not been saved then an error will get raised if the configuration option
10
+ # # was set.
11
+ # #
12
+ # # @example Reload the document.
13
+ # # person.reload
14
+ # #
15
+ # # @raise [ Errors::DocumentNotFound ] If the document was deleted.
16
+ # #
17
+ # # @return [ Document ] The document, reloaded.
18
+ # def reload_with_custom_fields
19
+ # reload_without_custom_fields.tap do
20
+ # instance_variable_names.each do |name|
21
+ # if name =~ /_proxy_class$/
22
+ # remove_instance_variable("#{name}")
23
+ # end
24
+ # end
25
+ # end
26
+ # end
27
+ #
28
+ # alias_method_chain :reload, :custom_fields
29
+ #
30
+ # end
31
+
4
32
  # This is the base module for all domain objects that need to be persisted to
5
33
  # the database as documents.
6
- module Document
34
+ module Reloading
7
35
 
8
36
  # Reloads the +Document+ attributes from the database. If the document has
9
37
  # not been saved then an error will get raised if the configuration option
@@ -4,26 +4,27 @@ module Mongoid # :nodoc:
4
4
 
5
5
  module Accessors
6
6
 
7
- # Create a relation from an object and metadata.
7
+ # Builds the related document and creates the relation based on the class
8
+ # enhanced by the custom_fields functionnality (if set up for the relation).
8
9
  #
9
- # @example Create the relation.
10
- # person.create_relation(document, metadata)
11
- #
12
- # @param [ Document, Array<Document ] object The relation target.
13
- # @param [ Metadata ] metadata The relation metadata.
10
+ # @param [ String, Symbol ] name The name of the relation.
11
+ # @param [ Hash, BSON::ObjectId ] object The id or attributes to use.
12
+ # @param [ Metadata ] metadata The relation's metadata.
13
+ # @param [ true, false ] building If we are in a build operation.
14
14
  #
15
15
  # @return [ Proxy ] The relation.
16
16
  #
17
17
  # @since 2.0.0.rc.1
18
- def create_relation_with_custom_fields(object, metadata)
18
+ def build_with_custom_fields(name, object, metadata)
19
19
  if self.respond_to?(:custom_fields_for?) && self.custom_fields_for?(metadata.name)
20
+ # puts "[Accessors] build_with_custom_fields #{name}"
20
21
  metadata = self.clone_metadata_for_custom_fields(metadata)
21
22
  end
22
23
 
23
- create_relation_without_custom_fields(object, metadata)
24
+ build_without_custom_fields(name, object, metadata)
24
25
  end
25
26
 
26
- alias_method_chain :create_relation, :custom_fields
27
+ alias_method_chain :build, :custom_fields
27
28
  end
28
29
 
29
30
  end
@@ -2,7 +2,6 @@ module Mongoid # :nodoc:
2
2
  module Relations #:nodoc:
3
3
 
4
4
  module Builders
5
- extend ActiveSupport::Concern
6
5
 
7
6
  module ClassMethods #:nodoc:
8
7
 
@@ -13,8 +12,12 @@ module Mongoid # :nodoc:
13
12
  metadata = self.clone_metadata_for_custom_fields(metadata)
14
13
  end
15
14
 
16
- document = Factory.build(metadata.klass, args.first || {})
17
- send("#{name}=", document, :binding => true)
15
+ attributes = args.first || {}
16
+ options = args.size > 1 ? args[1] : {}
17
+ document = Factory.build(metadata.klass, attributes, options)
18
+ _building do
19
+ send("#{name}=", document)
20
+ end
18
21
  end
19
22
  end
20
23
  end