default_value_for 2.0.3 → 3.0.0

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.
metadata.gz.asc CHANGED
@@ -2,11 +2,7 @@
2
2
  Version: GnuPG/MacGPG2 v2.0.17 (Darwin)
3
3
  Comment: GPGTools - http://gpgtools.org
4
4
 
5
- iQEcBAABAgAGBQJRnikCAAoJECrHRaUKISqMKUUIALD1qS846cCZWu67qXrkLy65
6
- yMS2APHvlz3EXfHUR2RAZ9HAagf5E+VR4XT+e4zJ51YrkH1vKLqIVyOf14FUbp3i
7
- 4a/34aZdKmmzy+4BO5qU/MqMeYd6e6kEWYy/YICYceGH3hrKZzO3gtsBfV9e7tzI
8
- VL/raxpG2XzLvHX5S/a1LCKcLRQQtrD3jp2BvUb1OcVzkxOWFCcfbLh/u1vC51i0
9
- V8IqRlBgJHPpKScyegVtCS1FSESjru5C3DgtqtYOyrshN4y+Fv6TuGfsMfnxt4XE
10
- HdUpPhEVtQQ52+MTWY11iQfLORLtvcQRk0NOO1ltoX1i3am2ZY9cIWDF2yqgQdU=
11
- =XHs9
5
+ iEYEABECAAYFAlLNhXUACgkQBqExCUtvQzJlagCfa5h4Zvo2ALI3QOtwFq3TE0QD
6
+ 1hMAnjL92O6u5fDrF2lXv/+sIZ02YvJT
7
+ =k8Of
12
8
  -----END PGP SIGNATURE-----
data/README.rdoc DELETED
@@ -1,510 +0,0 @@
1
- = Introduction
2
-
3
- The default_value_for plugin allows one to define default values for ActiveRecord
4
- models in a declarative manner. For example:
5
-
6
- class User < ActiveRecord::Base
7
- default_value_for :name, "(no name)"
8
- default_value_for :last_seen do
9
- Time.now
10
- end
11
- end
12
-
13
- u = User.new
14
- u.name # => "(no name)"
15
- u.last_seen # => Mon Sep 22 17:28:38 +0200 2008
16
-
17
- *Note*: critics might be interested in the "When (not) to use default_value_for?"
18
- section. Please read on.
19
-
20
-
21
- == Installation
22
-
23
- === Rails 3
24
-
25
- Add it to your Gemfile:
26
-
27
- gem "default_value_for"
28
-
29
- This gem is signed using PGP with the Phusion Software Signing key: http://www.phusion.nl/about/gpg. That key in turn is signed by the rubygems-openpgp Certificate Authority: http://www.rubygems-openpgp-ca.org/.
30
-
31
- You can verify the authenticity of the gem by following The Complete Guide to Verifying Gems with rubygems-openpgp: http://www.rubygems-openpgp-ca.org/blog/the-complete-guide-to-verifying-gems-with-rubygems-openpgp.html
32
-
33
- === Rails 2
34
-
35
- default_value_for no longer supports Rails 2! The last version that supported Rails
36
- 2 is version 1.0.7. Install that with:
37
-
38
- ./script/plugin install git://github.com/FooBarWidget/default_value_for.git -r release-1.0.7
39
-
40
-
41
- == The default_value_for method
42
-
43
- The +default_value_for+ method is available in all ActiveRecord model classes.
44
-
45
- The first argument is the name of the attribute for which a default value should
46
- be set. This may either be a Symbol or a String.
47
-
48
- The default value itself may either be passed as the second argument:
49
-
50
- default_value_for :age, 20
51
-
52
- ...or it may be passed as the return value of a block:
53
-
54
- default_value_for :age do
55
- if today_is_sunday?
56
- 20
57
- else
58
- 30
59
- end
60
- end
61
-
62
- If you pass a value argument, then the default value is static and never
63
- changes. However, if you pass a block, then the default value is retrieved by
64
- calling the block. This block is called not once, but every time a new record is
65
- instantiated and default values need to be filled in.
66
-
67
- The latter form is especially useful if your model has a UUID column. One can
68
- generate a new, random UUID for every newly instantiated record:
69
-
70
- class User < ActiveRecord::Base
71
- default_value_for :uuid do
72
- UuidGenerator.new.generate_uuid
73
- end
74
- end
75
-
76
- User.new.uuid # => "51d6d6846f1d1b5c9a...."
77
- User.new.uuid # => "ede292289e3484cb88...."
78
-
79
- Note that record is passed to the block as an argument, in case you need it for
80
- whatever reason:
81
-
82
- class User < ActiveRecord::Base
83
- default_value_for :uuid do |x|
84
- x # <--- a User object
85
- UuidGenerator.new.generate_uuid
86
- end
87
- end
88
-
89
- == default_value_for options
90
-
91
- * allows_nil (default: true) - Sets explicitly passed nil values if option is set to true.
92
-
93
- You can pass this options hash as 2nd parameter and have to pass the default value through the :value option in this case e.g.:
94
-
95
- default_value_for :age, :value => 20, :allows_nil => false
96
-
97
- You can still pass the default value through a block:
98
-
99
- default_value_for :uuid, :allows_nil => false do
100
- UuidGenerator.new.generate_uuid
101
- end
102
-
103
- == The default_values method
104
-
105
- As a shortcut, you can use +default_values+ to set multiple default values at once.
106
-
107
- default_values :age => 20,
108
- :uuid => lambda { UuidGenerator.new.generate_uuid }
109
-
110
- If you like to override default_value_for options for each attribute you can do so:
111
-
112
- default_values :age => { :value => 20 },
113
- :uuid => { :value => lambda { UuidGenerator.new.generate_uuid }, :allows_nil => false }
114
-
115
- The difference is purely aesthetic. If you have lots of default values which are constants or constructed with one-line blocks, +default_values+ may look nicer. If you have default values constructed by longer blocks, +default_value_for+ suit you better. Feel free to mix and match.
116
-
117
- As a side note, due to specifics of Ruby's parser, you cannot say,
118
-
119
- default_value_for :uuid { UuidGenerator.new.generate_uuid }
120
-
121
- because it will not parse. One needs to write
122
-
123
- default_value_for(:uuid) { UuidGenerator.new.generate_uuid }
124
-
125
- instead. This is in part the inspiration for the +default_values+ syntax.
126
-
127
- == Rules
128
-
129
- === Instantiation of new record
130
-
131
- Upon instantiating a new record, the declared default values are filled into
132
- the record. You've already seen this in the above examples.
133
-
134
- === Retrieval of existing record
135
-
136
- Upon retrieving an existing record in the following case, the declared default values are _not_
137
- filled into the record. Consider the example with the UUID:
138
-
139
- user = User.create
140
- user.uuid # => "529c91b8bbd3e..."
141
-
142
- user = User.find(user.id)
143
- # UUID remains unchanged because it's retrieved from the database!
144
- user.uuid # => "529c91b8bbd3e..."
145
-
146
- But when the declared default value is set to not allow nil and nil is passed the default values will be set on retrieval.
147
- Consider this example:
148
-
149
- default_value_for(:number, :allows_nil => false) { 123 }
150
-
151
- user = User.create
152
-
153
- # manual SQL by-passing active record and the default value for gem logic through ActiveRecord's after_initialize callback
154
- user.update_attribute(:number, nil)
155
-
156
- # declared default value should be set
157
- User.find(user.id).number # => 123 # = declared default value
158
-
159
- === Mass-assignment
160
-
161
- If a certain attribute is being assigned via the model constructor's
162
- mass-assignment argument, that the default value for that attribute will _not_
163
- be filled in:
164
-
165
- user = User.new(:uuid => "hello")
166
- user.uuid # => "hello"
167
-
168
- However, if that attribute is protected by +attr_protected+ or +attr_accessible+,
169
- then it will be filled in:
170
-
171
- class User < ActiveRecord::Base
172
- default_value_for :name, 'Joe'
173
- attr_protected :name
174
- end
175
-
176
- user = User.new(:name => "Jane")
177
- user.name # => "Joe"
178
-
179
- # the without protection option will work as expected
180
- user = User.new({:name => "Jane"}, :without_protection => true)
181
- user.name # => "Jane"
182
-
183
- Explicitly set nil values for accessible attributes will be accepted:
184
-
185
- class User < ActiveRecord::Base
186
- default_value_for :name, 'Joe'
187
- end
188
-
189
- user = User(:name => nil)
190
- user.name # => nil
191
-
192
- ... unless the accessible attribute is set to not allowing nil:
193
-
194
- class User < ActiveRecord::Base
195
- default_value_for :name, 'Joe', :allows_nil => false
196
- end
197
-
198
- user = User(:name => nil)
199
- user.name # => "Joe"
200
-
201
- === Inheritance
202
-
203
- Inheritance works as expected. All default values are inherited by the child
204
- class:
205
-
206
- class User < ActiveRecord::Base
207
- default_value_for :name, 'Joe'
208
- end
209
-
210
- class SuperUser < User
211
- end
212
-
213
- SuperUser.new.name # => "Joe"
214
-
215
- === Attributes that aren't database columns
216
-
217
- +default_value_for+ also works with attributes that aren't database columns.
218
- It works with anything for which there's an assignment method:
219
-
220
- # Suppose that your 'users' table only has a 'name' column.
221
- class User < ActiveRecord::Base
222
- default_value_for :name, 'Joe'
223
- default_value_for :age, 20
224
- default_value_for :registering, true
225
-
226
- attr_accessor :age
227
-
228
- def registering=(value)
229
- @registering = true
230
- end
231
- end
232
-
233
- user = User.new
234
- user.age # => 20
235
- user.instance_variable_get('@registering') # => true
236
-
237
- === Default values are duplicated
238
-
239
- The given default values are duplicated when they are filled in, so if
240
- you mutate a value that was filled in with a default value, then it will
241
- not affect all subsequent default values:
242
-
243
- class Author < ActiveRecord::Base
244
- # This model only has a 'name' attribute.
245
- end
246
-
247
- class Book < ActiveRecord::Base
248
- belongs_to :author
249
-
250
- # By default, a Book belongs to a new, unsaved author.
251
- default_value_for :author, Author.new
252
- end
253
-
254
- book1 = Book.new
255
- book1.author.name # => nil
256
- # This does not mutate the default value:
257
- book1.author.name = "John"
258
-
259
- book2 = Book.new
260
- book2.author.name # => nil
261
-
262
- However the duplication is shallow. If you modify any objects that are
263
- referenced by the default value then it will affect subsequent default values:
264
-
265
- class Author < ActiveRecord::Base
266
- attr_accessor :useless_hash
267
- default_value_for :useless_hash, { :foo => [] }
268
- end
269
-
270
- author1 = Author.new
271
- author1.useless_hash # => { :foo => [] }
272
- # This mutates the referred array:
273
- author1.useless_hash[:foo] << 1
274
-
275
- author2 = Author.new
276
- author2.useless_hash # => { :foo => [1] }
277
-
278
- You can prevent this from happening by passing a block to +default_value_for+,
279
- which returns a new object instance with fresh references every time:
280
-
281
- class Author < ActiveRecord::Base
282
- attr_accessor :useless_hash
283
- default_value_for :useless_hash do
284
- { :foo => [] }
285
- end
286
- end
287
-
288
- author1 = Author.new
289
- author1.useless_hash # => { :foo => [] }
290
- author1.useless_hash[:foo] << 1
291
-
292
- author2 = Author.new
293
- author2.useless_hash # => { :foo => [] }
294
-
295
- === Caveats
296
-
297
- A conflict can occur if your model class overrides the 'initialize' method,
298
- because this plugin overrides 'initialize' as well to do its job.
299
-
300
- class User < ActiveRecord::Base
301
- def initialize # <-- this constructor causes problems
302
- super(:name => 'Name cannot be changed in constructor')
303
- end
304
- end
305
-
306
- We recommend you to alias chain your initialize method in models where you use
307
- +default_value_for+:
308
-
309
- class User < ActiveRecord::Base
310
- default_value_for :age, 20
311
-
312
- def initialize_with_my_app
313
- initialize_without_my_app(:name => 'Name cannot be changed in constructor')
314
- end
315
-
316
- alias_method_chain :initialize, :my_app
317
- end
318
-
319
- Also, stick with the following rules:
320
- - There is no need to +alias_method_chain+ your initialize method in models that
321
- don't use +default_value_for+.
322
- - Make sure that +alias_method_chain+ is called *after* the last
323
- +default_value_for+ occurance.
324
-
325
- If your default value is accidentally similar to default_value_for's options hash wrap your default value like this:
326
-
327
- default_value_for :attribute_name, :value => { :value => 123, :other_value => 1234 }
328
-
329
- == When (not) to use default_value_for?
330
-
331
- You can also specify default values in the database schema. For example, you
332
- can specify a default value in a migration as follows:
333
-
334
- create_table :users do |t|
335
- t.string :username, :null => false, :default => 'default username'
336
- t.integer :age, :null => false, :default => 20
337
- end
338
-
339
- This has similar effects as passing the default value as the second argument to
340
- +default_value_for+:
341
-
342
- default_value_for(:username, 'default_username')
343
- default_value_for(:age, 20)
344
-
345
- Default values are filled in whether you use the schema defaults or the
346
- default_value_for defaults:
347
-
348
- user = User.new
349
- user.username # => 'default username'
350
- user.age # => 20
351
-
352
- It's recommended that you use this over +default_value_for+ whenever possible.
353
-
354
- However, it's not possible to specify a schema default for serialized columns.
355
- With +default_value_for+, you can:
356
-
357
- class User < ActiveRecord::Base
358
- serialize :color
359
- default_value_for :color, [255, 0, 0]
360
- end
361
-
362
- And if schema defaults don't provide the flexibility that you need, then
363
- +default_value_for+ is the perfect choice. For example, with +default_value_for+
364
- you could specify a per-environment default:
365
-
366
- class User < ActiveRecord::Base
367
- if Rails.env == "development"
368
- default_value_for :is_admin, true
369
- end
370
- end
371
-
372
- Or, as you've seen in an earlier example, you can use +default_value_for+ to
373
- generate a default random UUID:
374
-
375
- class User < ActiveRecord::Base
376
- default_value_for :uuid do
377
- UuidGenerator.new.generate_uuid
378
- end
379
- end
380
-
381
- Or you could use it to generate a timestamp that's relative to the time at which
382
- the record is instantiated:
383
-
384
- class User < ActiveRecord::Base
385
- default_value_for :account_expires_at do
386
- 3.years.from_now
387
- end
388
- end
389
-
390
- User.new.account_expires_at # => Mon Sep 22 18:43:42 +0200 2008
391
- sleep(2)
392
- User.new.account_expires_at # => Mon Sep 22 18:43:44 +0200 2008
393
-
394
- Finally, it's also possible to specify a default via an association:
395
-
396
- # Has columns: 'name' and 'default_price'
397
- class SuperMarket < ActiveRecord::Base
398
- has_many :products
399
- end
400
-
401
- # Has columns: 'name' and 'price'
402
- class Product < ActiveRecord::Base
403
- belongs_to :super_market
404
-
405
- default_value_for :price do |product|
406
- product.super_market.default_price
407
- end
408
- end
409
-
410
- super_market = SuperMarket.create(:name => 'Albert Zwijn', :default_price => 100)
411
- soap = super_market.products.create(:name => 'Soap')
412
- soap.price # => 100
413
-
414
- === What about before_validate/before_save?
415
-
416
- True, +before_validate+ and +before_save+ does what we want if we're only
417
- interested in filling in a default before saving. However, if one wants to be
418
- able to access the default value even before saving, then be prepared to write
419
- a lot of code. Suppose that we want to be able to access a new record's UUID,
420
- even before it's saved. We could end up with the following code:
421
-
422
- # In the controller
423
- def create
424
- @user = User.new(params[:user])
425
- @user.generate_uuid
426
- email_report_to_admin("#{@user.username} with UUID #{@user.uuid} created.")
427
- @user.save!
428
- end
429
-
430
- # Model
431
- class User < ActiveRecord::Base
432
- before_save :generate_uuid_if_necessary
433
-
434
- def generate_uuid
435
- self.uuid = ...
436
- end
437
-
438
- private
439
- def generate_uuid_if_necessary
440
- if uuid.blank?
441
- generate_uuid
442
- end
443
- end
444
- end
445
-
446
- The need to manually call +generate_uuid+ here is ugly, and one can easily forget
447
- to do that. Can we do better? Let's see:
448
-
449
- # Controller
450
- def create
451
- @user = User.new(params[:user])
452
- email_report_to_admin("#{@user.username} with UUID #{@user.uuid} created.")
453
- @user.save!
454
- end
455
-
456
- # Model
457
- class User < ActiveRecord::Base
458
- before_save :generate_uuid_if_necessary
459
-
460
- def uuid
461
- value = read_attribute('uuid')
462
- if !value
463
- value = generate_uuid
464
- write_attribute('uuid', value)
465
- end
466
- value
467
- end
468
-
469
- # We need to override this too, otherwise User.new.attributes won't return
470
- # a default UUID value. I've never tested with User.create() so maybe we
471
- # need to override even more things.
472
- def attributes
473
- uuid
474
- super
475
- end
476
-
477
- private
478
- def generate_uuid_if_necessary
479
- uuid # Reader method automatically generates UUID if it doesn't exist
480
- end
481
- end
482
-
483
- That's an awful lot of code. Using +default_value_for+ is easier, don't you think?
484
-
485
- === What about other plugins?
486
-
487
- I've only been able to find 2 similar plugins:
488
-
489
- - Default Value: http://agilewebdevelopment.com/plugins/default_value
490
- - ActiveRecord Defaults: http://agilewebdevelopment.com/plugins/activerecord_defaults
491
-
492
- 'Default Value' appears to be unmaintained; its SVN link is broken. This leaves
493
- only 'ActiveRecord Defaults'. However, it is semantically dubious, which leaves
494
- it wide open for corner cases. For example, it is not clearly specified what
495
- ActiveRecord Defaults will do when attributes are protected by +attr_protected+
496
- or +attr_accessible+. It is also not clearly specified what one is supposed to
497
- do if one needs a custom +initialize+ method in the model.
498
-
499
- I've taken my time to thoroughly document default_value_for's behavior.
500
-
501
-
502
- == Credits
503
-
504
- I've wanted such functionality for a while now and it baffled me that ActiveRecord
505
- doesn't provide a clean way for me to specify default values. After reading
506
- http://groups.google.com/group/rubyonrails-core/browse_thread/thread/b509a2fe2b62ac5/3e8243fa1954a935,
507
- it became clear that someone needs to write a plugin. This is the result.
508
-
509
- Thanks to Pratik Naik for providing the initial code snippet on which this plugin
510
- is based on: http://m.onkey.org/2007/7/24/how-to-set-default-values-in-your-model