custom_fields 1.0.0.beta.25 → 1.1.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +46 -3
- data/lib/custom_fields/custom_fields_for.rb +272 -116
- data/lib/custom_fields/extensions/active_support.rb +12 -0
- data/lib/custom_fields/extensions/mongoid/document.rb +29 -1
- data/lib/custom_fields/extensions/mongoid/relations/accessors.rb +10 -9
- data/lib/custom_fields/extensions/mongoid/relations/builders.rb +6 -3
- data/lib/custom_fields/field.rb +87 -51
- data/lib/custom_fields/proxy_class/base.rb +112 -0
- data/lib/custom_fields/proxy_class/builder.rb +60 -0
- data/lib/custom_fields/proxy_class/helper.rb +57 -0
- data/lib/custom_fields/{metadata.rb → self_metadata.rb} +3 -2
- data/lib/custom_fields/version.rb +3 -4
- data/lib/custom_fields.rb +16 -4
- metadata +88 -8
- data/lib/custom_fields/proxy_class_enabler.rb +0 -133
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.
|
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
|
-
|
51
|
+
company.save
|
11
52
|
|
12
|
-
|
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
|
-
|
16
|
-
|
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
|
-
|
121
|
+
# puts "-> clone_metadata_for_custom_fields #{metadata.name}"
|
21
122
|
|
22
|
-
klass = self.
|
123
|
+
klass = self.build_klass_with_custom_fields(metadata.name, metadata)
|
23
124
|
|
24
|
-
#
|
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
|
-
|
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
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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
|
-
|
61
|
-
self.
|
166
|
+
metadata = self.relations[name.to_s]
|
167
|
+
self.build(name, nil, metadata)
|
62
168
|
end
|
63
169
|
|
64
|
-
|
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
|
-
|
172
|
+
module ClassMethods
|
69
173
|
|
70
|
-
|
71
|
-
|
72
|
-
|
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
|
-
|
75
|
-
|
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
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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
|
-
|
84
|
-
|
236
|
+
self.custom_fields_for('self_metadata')
|
237
|
+
end
|
85
238
|
|
86
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
253
|
+
attr_accessor :"invalidate_#{name}_klass_flag" # flag for invalidating the custom class
|
114
254
|
|
115
|
-
accepts_nested_attributes_for
|
255
|
+
accepts_nested_attributes_for :"#{name}_custom_fields", :allow_destroy => true
|
256
|
+
end
|
116
257
|
|
117
|
-
|
118
|
-
self.#{singular_name}_custom_fields.sort { |a, b| (a.position || 0) <=> (b.position || 0) }
|
119
|
-
end
|
258
|
+
class_eval <<-EOV
|
120
259
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
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 #{
|
127
|
-
|
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 #{
|
132
|
-
self
|
270
|
+
def #{name}_klass_name
|
271
|
+
self.class.klass_name_with_custom_fields('#{name}', self)
|
133
272
|
end
|
134
273
|
|
135
|
-
def
|
136
|
-
|
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_#{
|
141
|
-
self.
|
278
|
+
def invalidate_#{name}_klass
|
279
|
+
self.invalidate_klass_with_custom_fields('#{name}')
|
142
280
|
end
|
143
|
-
EOV
|
144
281
|
|
145
|
-
|
146
|
-
|
282
|
+
def invalidate_#{name}_klass?
|
283
|
+
self.invalidate_klass_with_custom_fields?('#{name}')
|
284
|
+
end
|
147
285
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
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
|
-
|
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
|
-
|
301
|
+
def mark_#{name}_custom_fields_as_persisted
|
302
|
+
self.mark_custom_fields_as_persisted('#{name}')
|
303
|
+
end
|
158
304
|
|
159
|
-
|
160
|
-
|
161
|
-
|
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
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
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
|
-
|
178
|
-
|
179
|
-
|
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 => :#{
|
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
|
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
|
-
#
|
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
|
-
# @
|
10
|
-
#
|
11
|
-
#
|
12
|
-
# @param [
|
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
|
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
|
-
|
24
|
+
build_without_custom_fields(name, object, metadata)
|
24
25
|
end
|
25
26
|
|
26
|
-
alias_method_chain :
|
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
|
-
|
17
|
-
|
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
|