ta_default_value_for 3.4.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.
@@ -0,0 +1,37 @@
1
+ # Copyright (c) 2008, 2009, 2010, 2011 Phusion
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ module DefaultValueFor
22
+ def self.initialize_railtie
23
+ ActiveSupport.on_load :active_record do
24
+ DefaultValueFor.initialize_active_record_extensions
25
+ end
26
+ end
27
+
28
+ def self.initialize_active_record_extensions
29
+ ActiveRecord::Base.extend(DefaultValueFor::ClassMethods)
30
+ end
31
+
32
+ class Railtie < Rails::Railtie
33
+ initializer 'default_value_for.insert_into_active_record' do
34
+ DefaultValueFor.initialize_railtie
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,201 @@
1
+ # Copyright (c) 2008-2012 Phusion
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ module DefaultValueFor
22
+ class NormalValueContainer
23
+ def initialize(value)
24
+ @value = value
25
+ end
26
+
27
+ def evaluate(instance)
28
+ if @value.duplicable?
29
+ return @value.dup
30
+ else
31
+ return @value
32
+ end
33
+ end
34
+ end
35
+
36
+ class BlockValueContainer
37
+ def initialize(block)
38
+ @block = block
39
+ end
40
+
41
+ def evaluate(instance)
42
+ if @block.arity == 0
43
+ return @block.call
44
+ else
45
+ return @block.call(instance)
46
+ end
47
+ end
48
+ end
49
+
50
+ module ClassMethods
51
+ # Declares a default value for the given attribute.
52
+ #
53
+ # Sets the default value to the given options parameter unless the given options equal { :value => ... }
54
+ #
55
+ # The <tt>options</tt> can be used to specify the following things:
56
+ # * <tt>value</tt> - Sets the default value.
57
+ # * <tt>allows_nil (default: true)</tt> - Sets explicitly passed nil values if option is set to true.
58
+ def default_value_for(attribute, options = {}, &block)
59
+ value = options
60
+ allows_nil = true
61
+
62
+ if options.is_a?(Hash)
63
+ opts = options.stringify_keys
64
+ value = opts.fetch('value', options)
65
+ allows_nil = opts.fetch('allows_nil', true)
66
+ end
67
+
68
+ if !method_defined?(:set_default_values)
69
+ include(InstanceMethods)
70
+
71
+ after_initialize :set_default_values
72
+
73
+ class_attribute :_default_attribute_values
74
+ class_attribute :_default_attribute_values_not_allowing_nil
75
+
76
+ extend(DelayedClassMethods)
77
+ init_hash = true
78
+ else
79
+ init_hash = !singleton_methods(false).include?(:_default_attribute_values)
80
+ end
81
+
82
+ if init_hash
83
+ self._default_attribute_values = {}
84
+ self._default_attribute_values_not_allowing_nil = []
85
+ end
86
+
87
+ if block_given?
88
+ container = BlockValueContainer.new(block)
89
+ else
90
+ container = NormalValueContainer.new(value)
91
+ end
92
+ _default_attribute_values[attribute.to_s] = container
93
+ _default_attribute_values_not_allowing_nil << attribute.to_s unless allows_nil
94
+ end
95
+
96
+ def default_values(values)
97
+ values.each_pair do |key, options|
98
+ options = options.stringify_keys if options.is_a?(Hash)
99
+
100
+ value = options.is_a?(Hash) && options.has_key?('value') ? options['value'] : options
101
+
102
+ if value.kind_of? Proc
103
+ default_value_for(key, options.is_a?(Hash) ? options : {}, &value)
104
+ else
105
+ default_value_for(key, options)
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ module DelayedClassMethods
112
+ def _all_default_attribute_values
113
+ return _default_attribute_values unless superclass.respond_to?(:_default_attribute_values)
114
+ superclass._all_default_attribute_values.merge(_default_attribute_values)
115
+ end
116
+
117
+ def _all_default_attribute_values_not_allowing_nil
118
+ return _default_attribute_values_not_allowing_nil unless superclass.respond_to?(:_default_attribute_values_not_allowing_nil)
119
+ result = superclass._all_default_attribute_values_not_allowing_nil + _default_attribute_values_not_allowing_nil
120
+ result.uniq!
121
+ result
122
+ end
123
+ end
124
+
125
+ module InstanceMethods
126
+ def initialize(attributes = nil, options = {})
127
+ attributes = attributes.to_h if attributes.respond_to?(:to_h)
128
+ @initialization_attributes = attributes.is_a?(Hash) ? attributes.stringify_keys : {}
129
+
130
+ unless options[:without_protection]
131
+ if respond_to?(:mass_assignment_options, true) && options.has_key?(:as)
132
+ @initialization_attributes = sanitize_for_mass_assignment(@initialization_attributes, options[:as])
133
+ elsif respond_to?(:sanitize_for_mass_assignment, true)
134
+ @initialization_attributes = sanitize_for_mass_assignment(@initialization_attributes)
135
+ else
136
+ @initialization_attributes = remove_attributes_protected_from_mass_assignment(@initialization_attributes)
137
+ end
138
+ end
139
+
140
+ if self.class.respond_to? :protected_attributes
141
+ super(attributes, options)
142
+ else
143
+ super(attributes)
144
+ end
145
+ end
146
+
147
+ def attributes_for_create(attribute_names)
148
+ attribute_names += self.class._all_default_attribute_values.keys.map(&:to_s).find_all { |name|
149
+ self.class.columns_hash.key?(name)
150
+ }
151
+ super
152
+ end
153
+
154
+ def set_default_values
155
+ self.class._all_default_attribute_values.each do |attribute, container|
156
+ next unless new_record? || self.class._all_default_attribute_values_not_allowing_nil.include?(attribute)
157
+
158
+ connection_default_value_defined = new_record? && respond_to?("#{attribute}_changed?") && !__send__("#{attribute}_changed?")
159
+
160
+ attribute_blank = if attributes.has_key?(attribute)
161
+ column = self.class.columns_hash[attribute]
162
+ if column && column.type == :boolean
163
+ attributes[attribute].nil?
164
+ else
165
+ attributes[attribute].blank?
166
+ end
167
+ elsif respond_to?(attribute)
168
+ send(attribute).nil?
169
+ else
170
+ instance_variable_get("@#{attribute}").nil?
171
+ end
172
+ next unless connection_default_value_defined || attribute_blank
173
+
174
+ # allow explicitly setting nil through allow nil option
175
+ next if @initialization_attributes.is_a?(Hash) &&
176
+ (
177
+ @initialization_attributes.has_key?(attribute) ||
178
+ (
179
+ @initialization_attributes.has_key?("#{attribute}_attributes") &&
180
+ nested_attributes_options.stringify_keys[attribute]
181
+ )
182
+ ) &&
183
+ !self.class._all_default_attribute_values_not_allowing_nil.include?(attribute)
184
+
185
+ __send__("#{attribute}=", container.evaluate(self))
186
+ if respond_to?(:clear_attribute_changes, true)
187
+ clear_attribute_changes [attribute] if has_attribute?(attribute)
188
+ else
189
+ changed_attributes.delete(attribute)
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
195
+
196
+ if defined?(Rails::Railtie)
197
+ require 'default_value_for/railtie'
198
+ else
199
+ # For anybody is using AS and AR without Railties, i.e. Padrino.
200
+ ActiveRecord::Base.extend(DefaultValueFor::ClassMethods)
201
+ end
data/test.rb ADDED
@@ -0,0 +1,461 @@
1
+ # Copyright (c) 2008-2012 Phusion
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'bundler/setup'
22
+ require 'minitest/autorun'
23
+ require 'minitest/around/unit'
24
+ require 'active_record'
25
+ require 'action_pack'
26
+
27
+ if ActiveSupport::VERSION::MAJOR == 3
28
+ require 'active_support/core_ext/logger'
29
+ end
30
+
31
+ if ActionPack::VERSION::MAJOR > 3
32
+ require 'action_controller'
33
+ end
34
+
35
+ # Handle an edge-case when using Arel 5 (i.e. Rails <= 4.1) with Ruby >= 2.4:
36
+ # See: https://github.com/rails/arel/commit/dc85a6e9c74942945ad696f5da4d82490a85b865
37
+ # See: https://stackoverflow.com/a/51481088
38
+ rails_match_data = RUBY_VERSION.match(/\A(?<major>\d+).(?<minor>\d+)/)
39
+ rails_2_4_or_newer = rails_match_data[:major].to_i > 2 || (rails_match_data[:major].to_i == 2 && rails_match_data[:minor].to_i >= 4)
40
+ arel_match_data = Arel::VERSION.match(/\A(?<major>\d+).(?<minor>\d+)/)
41
+ arel_older_than_7_1 = arel_match_data[:major].to_i < 7 || (arel_match_data[:major].to_i == 7 && arel_match_data[:minor].to_i < 1)
42
+
43
+ if rails_2_4_or_newer && arel_older_than_7_1
44
+ module Arel
45
+ module Visitors
46
+ class DepthFirst < Arel::Visitors::Visitor
47
+ alias :visit_Integer :terminal
48
+ end
49
+
50
+ class Dot < Arel::Visitors::Visitor
51
+ alias :visit_Integer :visit_String
52
+ end
53
+
54
+ # The super class for ToSql changed with Arel 6
55
+ # See: https://github.com/rails/arel/commit/a6a7c75ff486657909e20e2f48764136caa5e87e#diff-3538aead5b80677372eea0e903ff728eR7
56
+ class ToSql < (Arel::VERSION[/\A\d+/].to_i >= 6 ? Arel::Visitors::Reduce : Arel::Visitors::Visitor)
57
+ alias :visit_Integer :literal
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ begin
64
+ TestCaseClass = MiniTest::Test
65
+ rescue NameError
66
+ TestCaseClass = MiniTest::Unit::TestCase
67
+ end
68
+
69
+ require 'default_value_for'
70
+
71
+ puts "\nTesting with Active Record version #{ActiveRecord::VERSION::STRING}"
72
+ puts "\nTesting with Action Pack version #{ActionPack::VERSION::STRING}\n\n"
73
+
74
+ ActiveRecord::Base.default_timezone = :local
75
+ ActiveRecord::Base.logger = Logger.new(STDERR)
76
+ ActiveRecord::Base.logger.level = Logger::WARN
77
+
78
+ ActiveRecord::Base.establish_connection(
79
+ :adapter => RUBY_PLATFORM == 'java' ? 'jdbcsqlite3' : 'sqlite3',
80
+ :database => ':memory:'
81
+ )
82
+
83
+ ActiveRecord::Base.connection.create_table(:users, :force => true) do |t|
84
+ t.string :username
85
+ t.integer :default_number
86
+ t.text :settings
87
+ end
88
+
89
+ ActiveRecord::Base.connection.create_table(:books, :force => true) do |t|
90
+ t.string :type
91
+ t.integer :number
92
+ t.integer :count, :null => false, :default => 1
93
+ t.integer :user_id
94
+ t.timestamp :timestamp
95
+ t.text :stuff
96
+ t.boolean :flag
97
+ end
98
+
99
+ if defined?(Rails::Railtie)
100
+ DefaultValueFor.initialize_railtie
101
+ DefaultValueFor.initialize_active_record_extensions
102
+ end
103
+
104
+ class DefaultValuePluginTest < TestCaseClass
105
+ def around
106
+ Object.const_set(:User, Class.new(ActiveRecord::Base))
107
+ Object.const_set(:Book, Class.new(ActiveRecord::Base))
108
+ Object.const_set(:Novel, Class.new(Book))
109
+ User.has_many :books
110
+ Book.belongs_to :user
111
+
112
+ ActiveRecord::Base.transaction do
113
+ yield
114
+ raise ActiveRecord::Rollback
115
+ end
116
+ ensure
117
+ Object.send(:remove_const, :User)
118
+ Object.send(:remove_const, :Book)
119
+ Object.send(:remove_const, :Novel)
120
+ ActiveSupport::Dependencies.clear unless ActiveSupport::VERSION::MAJOR > 6
121
+ end
122
+
123
+ def test_default_value_on_attribute_methods
124
+ Book.class_eval do
125
+ serialize :stuff
126
+ default_value_for :color, :green
127
+ def color; (self.stuff || {})[:color]; end
128
+ def color=(val)
129
+ self.stuff ||= {}
130
+ self.stuff[:color] = val
131
+ end
132
+ end
133
+ assert_equal :green, Book.create.color
134
+ end
135
+
136
+ def test_default_value_can_be_passed_as_argument
137
+ Book.default_value_for(:number, 1234)
138
+ assert_equal 1234, Book.new.number
139
+ end
140
+
141
+ def test_default_value_can_be_passed_as_block
142
+ Book.default_value_for(:number) { 1234 }
143
+ assert_equal 1234, Book.new.number
144
+ end
145
+
146
+ def test_works_with_create
147
+ Book.default_value_for :number, 1234
148
+
149
+ object = Book.create
150
+ refute_nil Book.find_by_number(1234)
151
+
152
+ # allows nil for existing records
153
+ object.update_attribute(:number, nil)
154
+ assert_nil Book.find_by_number(1234)
155
+ assert_nil Book.find(object.id).number
156
+ end
157
+
158
+ def test_does_not_allow_nil_sets_default_value_on_existing_nils
159
+ Book.default_value_for(:number, :allows_nil => false) { 1234 }
160
+ object = Book.create
161
+ object.update_attribute(:number, nil)
162
+ assert_nil Book.find_by_number(1234)
163
+ assert_equal 1234, Book.find(object.id).number
164
+ end
165
+
166
+ def test_overwrites_db_default
167
+ Book.default_value_for :count, 1234
168
+ assert_equal 1234, Book.new.count
169
+ end
170
+
171
+ def test_doesnt_overwrite_values_provided_by_mass_assignment
172
+ Book.default_value_for :number, 1234
173
+ assert_equal 1, Book.new(:number => 1, :count => 2).number
174
+ end
175
+
176
+ def test_doesnt_overwrite_values_provided_by_multiparameter_assignment
177
+ Book.default_value_for :timestamp, Time.mktime(2000, 1, 1)
178
+ timestamp = Time.mktime(2009, 1, 1)
179
+ object = Book.new('timestamp(1i)' => '2009', 'timestamp(2i)' => '1', 'timestamp(3i)' => '1')
180
+ assert_equal timestamp, object.timestamp
181
+ end
182
+
183
+ def test_doesnt_overwrite_values_provided_by_constructor_block
184
+ Book.default_value_for :number, 1234
185
+ object = Book.new do |x|
186
+ x.number = 1
187
+ x.count = 2
188
+ end
189
+ assert_equal 1, object.number
190
+ end
191
+
192
+ def test_doesnt_overwrite_explicitly_provided_nil_values_in_mass_assignment
193
+ Book.default_value_for :number, 1234
194
+ assert_nil Book.new(:number => nil).number
195
+ end
196
+
197
+ def test_overwrites_explicitly_provided_nil_values_in_mass_assignment
198
+ Book.default_value_for :number, :value => 1234, :allows_nil => false
199
+ assert_equal 1234, Book.new(:number => nil).number
200
+ end
201
+
202
+ def test_default_values_are_inherited
203
+ Book.default_value_for :number, 1234
204
+ assert_equal 1234, Novel.new.number
205
+ end
206
+
207
+ def test_default_values_in_superclass_are_saved_in_subclass
208
+ Book.default_value_for :number, 1234
209
+ Novel.default_value_for :flag, true
210
+ object = Novel.create!
211
+ assert_equal object.id, Novel.find_by_number(1234).id
212
+ assert_equal object.id, Novel.find_by_flag(true).id
213
+ end
214
+
215
+ def test_default_values_in_subclass
216
+ Novel.default_value_for :number, 5678
217
+ assert_equal 5678, Novel.new.number
218
+ assert_nil Book.new.number
219
+ end
220
+
221
+ def test_multiple_default_values_in_subclass_with_default_values_in_parent_class
222
+ Book.class_eval do
223
+ default_value_for :other_number, nil
224
+ attr_accessor :other_number
225
+ end
226
+ Novel.default_value_for :number, 5678
227
+
228
+ # Ensure second call in this class doesn't reset _default_attribute_values,
229
+ # and also doesn't consider the parent class' _default_attribute_values when
230
+ # making that check.
231
+ Novel.default_value_for :user_id, 9999
232
+
233
+ object = Novel.new
234
+ assert_nil object.other_number
235
+ assert_equal 5678, object.number
236
+ assert_equal 9999, object.user_id
237
+ end
238
+
239
+ def test_override_default_values_in_subclass
240
+ Book.default_value_for :number, 1234
241
+ Novel.default_value_for :number, 5678
242
+ assert_equal 5678, Novel.new.number
243
+ assert_equal 1234, Book.new.number
244
+ end
245
+
246
+ def test_default_values_in_subclass_do_not_affect_parent_class
247
+ Book.default_value_for :number, 1234
248
+ Novel.class_eval do
249
+ default_value_for :hello, "hi"
250
+ attr_accessor :hello
251
+ end
252
+
253
+ assert Book.new
254
+ assert !Book._default_attribute_values.include?(:hello)
255
+ end
256
+
257
+ def test_doesnt_set_default_on_saved_records
258
+ Book.create(:number => 9876)
259
+ Book.default_value_for :number, 1234
260
+ assert_equal 9876, Book.first.number
261
+ end
262
+
263
+ def test_also_works_on_attributes_that_arent_database_columns
264
+ Book.class_eval do
265
+ default_value_for :hello, "hi"
266
+ attr_accessor :hello
267
+ end
268
+ assert_equal 'hi', Book.new.hello
269
+ end
270
+
271
+ def test_works_on_attributes_that_only_have_writers
272
+ Book.class_eval do
273
+ default_value_for :hello, "hi"
274
+ attr_writer :hello
275
+ end
276
+ assert_equal 'hi', Book.new.instance_variable_get('@hello')
277
+ end
278
+
279
+ def test_doesnt_conflict_with_overrided_initialize_method_in_model_class
280
+ Book.class_eval do
281
+ def initialize(attrs = {})
282
+ @initialized = true
283
+ super(:count => 5678)
284
+ end
285
+
286
+ default_value_for :number, 1234
287
+ end
288
+ object = Book.new
289
+ assert_equal 1234, object.number
290
+ assert_equal 5678, object.count
291
+ assert object.instance_variable_get('@initialized')
292
+ end
293
+
294
+ def test_model_instance_is_passed_to_the_given_block
295
+ instance = nil
296
+ Book.default_value_for :number do |n|
297
+ instance = n
298
+ end
299
+ object = Book.new
300
+ assert_same object.object_id, instance.object_id
301
+ end
302
+
303
+ def test_can_specify_default_value_via_association
304
+ user = User.create(:username => 'Kanako', :default_number => 123)
305
+ Book.default_value_for :number do |n|
306
+ n.user.default_number
307
+ end
308
+ assert_equal 123, user.books.create!.number
309
+ end
310
+
311
+ def test_default_values
312
+ Book.default_values({
313
+ :type => "normal",
314
+ :number => lambda { 10 + 5 },
315
+ :timestamp => lambda {|_| Time.now }
316
+ })
317
+
318
+ object = Book.new
319
+ assert_equal("normal", object.type)
320
+ assert_equal(15, object.number)
321
+ end
322
+
323
+ def test_default_value_order
324
+ Book.default_value_for :count, 5
325
+ Book.default_value_for :number do |this|
326
+ this.count * 2
327
+ end
328
+ object = Book.new
329
+ assert_equal(5, object.count)
330
+ assert_equal(10, object.number)
331
+ end
332
+
333
+ def test_attributes_with_default_values_are_not_marked_as_changed
334
+ Book.default_value_for :count, 5
335
+ Book.default_value_for :number, 2
336
+
337
+ object = Book.new
338
+ assert(!object.changed?)
339
+ assert_equal([], object.changed)
340
+
341
+ object.type = "foo"
342
+ assert(object.changed?)
343
+ assert_equal(["type"], object.changed)
344
+ end
345
+
346
+ def test_default_values_are_duplicated
347
+ User.default_value_for :username, "hello"
348
+ user1 = User.new
349
+ user1.username << " world"
350
+ user2 = User.new
351
+ assert_equal("hello", user2.username)
352
+ end
353
+
354
+ def test_default_values_are_shallow_copied
355
+ User.class_eval do
356
+ attr_accessor :hash
357
+ default_value_for :hash, { 1 => [] }
358
+ end
359
+ user1 = User.new
360
+ user1.hash[1] << 1
361
+ user2 = User.new
362
+ assert_equal([1], user2.hash[1])
363
+ end
364
+
365
+ def test_constructor_does_not_affect_the_hash_passed_to_it
366
+ Book.default_value_for :count, 5
367
+ options = { :count => 5, :user_id => 1 }
368
+ options_dup = options.dup
369
+ Book.new(options)
370
+ assert_equal(options_dup, options)
371
+ end
372
+
373
+ def test_subclass_find
374
+ Book.default_value_for :number, 5678
375
+ n = Novel.create
376
+ assert Novel.find(n.id)
377
+ end
378
+
379
+ def test_does_not_see_false_as_blank_at_boolean_columns_for_existing_records
380
+ Book.default_value_for(:flag, :allows_nil => false) { true }
381
+
382
+ object = Book.create
383
+
384
+ # allows nil for existing records
385
+ object.update_attribute(:flag, false)
386
+ assert_equal false, Book.find(object.id).flag
387
+ end
388
+
389
+ def test_works_with_nested_attributes
390
+ User.accepts_nested_attributes_for :books
391
+ User.default_value_for :books do
392
+ [Book.create!(:number => 0)]
393
+ end
394
+
395
+ user = User.create! :books_attributes => [{:number => 1}]
396
+ assert_equal 1, Book.all.first.number
397
+ end
398
+
399
+ def test_works_with_stored_attribute_accessors_when_initializing_value_that_does_not_allow_nil
400
+ User.store :settings, :accessors => :bio
401
+ User.default_value_for :bio, :value => 'None given', :allows_nil => false
402
+
403
+ user = User.create!(:bio => 'This is a bio')
404
+ assert_equal 'This is a bio', user.bio
405
+ end
406
+
407
+ if ActionPack::VERSION::MAJOR > 3
408
+ def test_doesnt_overwrite_explicitly_provided_nil_values_in_mass_assignment_with_action_controller_parameters
409
+ Book.default_value_for :number, 1234
410
+
411
+ assert_nil Book.new(ActionController::Parameters.new(:number => nil).permit!).number
412
+ end
413
+
414
+ def test_overwrites_explicitly_provided_nil_values_in_mass_assignment_with_action_controller_parameters
415
+ Book.default_value_for :number, :value => 1234, :allows_nil => false
416
+
417
+ assert_equal 1234, Book.new(ActionController::Parameters.new(:number => nil).permit!).number
418
+ end
419
+
420
+ def test_works_with_nested_attributes_with_action_controller_parameters
421
+ User.accepts_nested_attributes_for :books
422
+ User.default_value_for :books do
423
+ [Book.create!(:number => 0)]
424
+ end
425
+
426
+ user = User.create!(ActionController::Parameters.new(:books_attributes => [{:number => 1}]).permit!)
427
+ assert_equal 1, Book.all.first.number
428
+ end
429
+
430
+ def test_works_with_stored_attribute_accessors_when_initializing_value_that_does_not_allow_nil_with_action_controller_parameters
431
+ User.store :settings, :accessors => :bio
432
+ User.default_value_for :bio, :value => 'None given', :allows_nil => false
433
+
434
+ user = User.create!(ActionController::Parameters.new(:bio => 'This is a bio').permit!)
435
+ assert_equal 'This is a bio', user.bio
436
+ end
437
+ end
438
+
439
+ if ActiveRecord::VERSION::MAJOR == 3
440
+ def test_constructor_ignores_forbidden_mass_assignment_attributes
441
+ Book.class_eval do
442
+ default_value_for :number, 1234
443
+ attr_protected :number
444
+ end
445
+ object = Book.new(:number => 5678, :count => 987)
446
+ assert_equal 1234, object.number
447
+ assert_equal 987, object.count
448
+ end
449
+
450
+ def test_constructor_respects_without_protection_option
451
+ Book.class_eval do
452
+ default_value_for :number, 1234
453
+ attr_protected :number
454
+ end
455
+
456
+ object = Book.create!({:number => 5678, :count => 987}, :without_protection => true)
457
+ assert_equal 5678, object.number
458
+ assert_equal 987, object.count
459
+ end
460
+ end
461
+ end