activemodel 4.2.0 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +49 -37
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +16 -22
  5. data/lib/active_model/attribute/user_provided_default.rb +51 -0
  6. data/lib/active_model/attribute.rb +248 -0
  7. data/lib/active_model/attribute_assignment.rb +55 -0
  8. data/lib/active_model/attribute_methods.rb +150 -73
  9. data/lib/active_model/attribute_mutation_tracker.rb +181 -0
  10. data/lib/active_model/attribute_set/builder.rb +191 -0
  11. data/lib/active_model/attribute_set/yaml_encoder.rb +40 -0
  12. data/lib/active_model/attribute_set.rb +106 -0
  13. data/lib/active_model/attributes.rb +132 -0
  14. data/lib/active_model/callbacks.rb +31 -25
  15. data/lib/active_model/conversion.rb +20 -9
  16. data/lib/active_model/dirty.rb +142 -116
  17. data/lib/active_model/error.rb +207 -0
  18. data/lib/active_model/errors.rb +436 -202
  19. data/lib/active_model/forbidden_attributes_protection.rb +6 -3
  20. data/lib/active_model/gem_version.rb +5 -3
  21. data/lib/active_model/lint.rb +47 -42
  22. data/lib/active_model/locale/en.yml +2 -1
  23. data/lib/active_model/model.rb +7 -7
  24. data/lib/active_model/naming.rb +36 -18
  25. data/lib/active_model/nested_error.rb +22 -0
  26. data/lib/active_model/railtie.rb +8 -0
  27. data/lib/active_model/secure_password.rb +61 -67
  28. data/lib/active_model/serialization.rb +48 -17
  29. data/lib/active_model/serializers/json.rb +22 -13
  30. data/lib/active_model/translation.rb +5 -4
  31. data/lib/active_model/type/big_integer.rb +14 -0
  32. data/lib/active_model/type/binary.rb +52 -0
  33. data/lib/active_model/type/boolean.rb +46 -0
  34. data/lib/active_model/type/date.rb +52 -0
  35. data/lib/active_model/type/date_time.rb +46 -0
  36. data/lib/active_model/type/decimal.rb +69 -0
  37. data/lib/active_model/type/float.rb +35 -0
  38. data/lib/active_model/type/helpers/accepts_multiparameter_time.rb +49 -0
  39. data/lib/active_model/type/helpers/mutable.rb +20 -0
  40. data/lib/active_model/type/helpers/numeric.rb +48 -0
  41. data/lib/active_model/type/helpers/time_value.rb +90 -0
  42. data/lib/active_model/type/helpers/timezone.rb +19 -0
  43. data/lib/active_model/type/helpers.rb +7 -0
  44. data/lib/active_model/type/immutable_string.rb +35 -0
  45. data/lib/active_model/type/integer.rb +67 -0
  46. data/lib/active_model/type/registry.rb +70 -0
  47. data/lib/active_model/type/string.rb +35 -0
  48. data/lib/active_model/type/time.rb +46 -0
  49. data/lib/active_model/type/value.rb +133 -0
  50. data/lib/active_model/type.rb +53 -0
  51. data/lib/active_model/validations/absence.rb +6 -4
  52. data/lib/active_model/validations/acceptance.rb +72 -14
  53. data/lib/active_model/validations/callbacks.rb +23 -19
  54. data/lib/active_model/validations/clusivity.rb +18 -12
  55. data/lib/active_model/validations/confirmation.rb +27 -14
  56. data/lib/active_model/validations/exclusion.rb +7 -4
  57. data/lib/active_model/validations/format.rb +27 -27
  58. data/lib/active_model/validations/helper_methods.rb +15 -0
  59. data/lib/active_model/validations/inclusion.rb +8 -7
  60. data/lib/active_model/validations/length.rb +35 -32
  61. data/lib/active_model/validations/numericality.rb +72 -34
  62. data/lib/active_model/validations/presence.rb +3 -3
  63. data/lib/active_model/validations/validates.rb +17 -15
  64. data/lib/active_model/validations/with.rb +6 -12
  65. data/lib/active_model/validations.rb +58 -23
  66. data/lib/active_model/validator.rb +23 -17
  67. data/lib/active_model/version.rb +4 -2
  68. data/lib/active_model.rb +18 -11
  69. metadata +44 -25
  70. data/lib/active_model/serializers/xml.rb +0 -238
  71. data/lib/active_model/test_case.rb +0 -4
@@ -0,0 +1,191 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model/attribute"
4
+
5
+ module ActiveModel
6
+ class AttributeSet # :nodoc:
7
+ class Builder # :nodoc:
8
+ attr_reader :types, :default_attributes
9
+
10
+ def initialize(types, default_attributes = {})
11
+ @types = types
12
+ @default_attributes = default_attributes
13
+ end
14
+
15
+ def build_from_database(values = {}, additional_types = {})
16
+ LazyAttributeSet.new(values, types, additional_types, default_attributes)
17
+ end
18
+ end
19
+ end
20
+
21
+ class LazyAttributeSet < AttributeSet # :nodoc:
22
+ def initialize(values, types, additional_types, default_attributes, attributes = {})
23
+ super(attributes)
24
+ @values = values
25
+ @types = types
26
+ @additional_types = additional_types
27
+ @default_attributes = default_attributes
28
+ @casted_values = {}
29
+ @materialized = false
30
+ end
31
+
32
+ def key?(name)
33
+ (values.key?(name) || types.key?(name) || @attributes.key?(name)) && self[name].initialized?
34
+ end
35
+
36
+ def keys
37
+ keys = values.keys | types.keys | @attributes.keys
38
+ keys.keep_if { |name| self[name].initialized? }
39
+ end
40
+
41
+ def fetch_value(name, &block)
42
+ if attr = @attributes[name]
43
+ return attr.value(&block)
44
+ end
45
+
46
+ @casted_values.fetch(name) do
47
+ value_present = true
48
+ value = values.fetch(name) { value_present = false }
49
+
50
+ if value_present
51
+ type = additional_types.fetch(name, types[name])
52
+ @casted_values[name] = type.deserialize(value)
53
+ else
54
+ attr = default_attribute(name, value_present, value)
55
+ attr.value(&block)
56
+ end
57
+ end
58
+ end
59
+
60
+ protected
61
+ def attributes
62
+ unless @materialized
63
+ values.each_key { |key| self[key] }
64
+ types.each_key { |key| self[key] }
65
+ @materialized = true
66
+ end
67
+ @attributes
68
+ end
69
+
70
+ private
71
+ attr_reader :values, :types, :additional_types, :default_attributes
72
+
73
+ def default_attribute(
74
+ name,
75
+ value_present = true,
76
+ value = values.fetch(name) { value_present = false }
77
+ )
78
+ type = additional_types.fetch(name, types[name])
79
+
80
+ if value_present
81
+ @attributes[name] = Attribute.from_database(name, value, type, @casted_values[name])
82
+ elsif types.key?(name)
83
+ if attr = default_attributes[name]
84
+ @attributes[name] = attr.dup
85
+ else
86
+ @attributes[name] = Attribute.uninitialized(name, type)
87
+ end
88
+ else
89
+ Attribute.null(name)
90
+ end
91
+ end
92
+ end
93
+
94
+ class LazyAttributeHash # :nodoc:
95
+ delegate :transform_values, :each_value, :fetch, :except, to: :materialize
96
+
97
+ def initialize(types, values, additional_types, default_attributes, delegate_hash = {})
98
+ @types = types
99
+ @values = values
100
+ @additional_types = additional_types
101
+ @materialized = false
102
+ @delegate_hash = delegate_hash
103
+ @default_attributes = default_attributes
104
+ end
105
+
106
+ def key?(key)
107
+ delegate_hash.key?(key) || values.key?(key) || types.key?(key)
108
+ end
109
+
110
+ def [](key)
111
+ delegate_hash[key] || assign_default_value(key)
112
+ end
113
+
114
+ def []=(key, value)
115
+ delegate_hash[key] = value
116
+ end
117
+
118
+ def deep_dup
119
+ dup.tap do |copy|
120
+ copy.instance_variable_set(:@delegate_hash, delegate_hash.transform_values(&:dup))
121
+ end
122
+ end
123
+
124
+ def initialize_dup(_)
125
+ @delegate_hash = Hash[delegate_hash]
126
+ super
127
+ end
128
+
129
+ def each_key(&block)
130
+ keys = types.keys | values.keys | delegate_hash.keys
131
+ keys.each(&block)
132
+ end
133
+
134
+ def ==(other)
135
+ if other.is_a?(LazyAttributeHash)
136
+ materialize == other.materialize
137
+ else
138
+ materialize == other
139
+ end
140
+ end
141
+
142
+ def marshal_dump
143
+ [@types, @values, @additional_types, @default_attributes, @delegate_hash]
144
+ end
145
+
146
+ def marshal_load(values)
147
+ if values.is_a?(Hash)
148
+ ActiveSupport::Deprecation.warn(<<~MSG)
149
+ Marshalling load from legacy attributes format is deprecated and will be removed in Rails 6.2.
150
+ MSG
151
+ empty_hash = {}.freeze
152
+ initialize(empty_hash, empty_hash, empty_hash, empty_hash, values)
153
+ @materialized = true
154
+ else
155
+ initialize(*values)
156
+ end
157
+ end
158
+
159
+ protected
160
+ def materialize
161
+ unless @materialized
162
+ values.each_key { |key| self[key] }
163
+ types.each_key { |key| self[key] }
164
+ unless frozen?
165
+ @materialized = true
166
+ end
167
+ end
168
+ delegate_hash
169
+ end
170
+
171
+ private
172
+ attr_reader :types, :values, :additional_types, :delegate_hash, :default_attributes
173
+
174
+ def assign_default_value(name)
175
+ type = additional_types.fetch(name, types[name])
176
+ value_present = true
177
+ value = values.fetch(name) { value_present = false }
178
+
179
+ if value_present
180
+ delegate_hash[name] = Attribute.from_database(name, value, type)
181
+ elsif types.key?(name)
182
+ attr = default_attributes[name]
183
+ if attr
184
+ delegate_hash[name] = attr.dup
185
+ else
186
+ delegate_hash[name] = Attribute.uninitialized(name, type)
187
+ end
188
+ end
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveModel
4
+ class AttributeSet
5
+ # Attempts to do more intelligent YAML dumping of an
6
+ # ActiveModel::AttributeSet to reduce the size of the resulting string
7
+ class YAMLEncoder # :nodoc:
8
+ def initialize(default_types)
9
+ @default_types = default_types
10
+ end
11
+
12
+ def encode(attribute_set, coder)
13
+ coder["concise_attributes"] = attribute_set.each_value.map do |attr|
14
+ if attr.type.equal?(default_types[attr.name])
15
+ attr.with_type(nil)
16
+ else
17
+ attr
18
+ end
19
+ end
20
+ end
21
+
22
+ def decode(coder)
23
+ if coder["attributes"]
24
+ coder["attributes"]
25
+ else
26
+ attributes_hash = Hash[coder["concise_attributes"].map do |attr|
27
+ if attr.type.nil?
28
+ attr = attr.with_type(default_types[attr.name])
29
+ end
30
+ [attr.name, attr]
31
+ end]
32
+ AttributeSet.new(attributes_hash)
33
+ end
34
+ end
35
+
36
+ private
37
+ attr_reader :default_types
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/enumerable"
4
+ require "active_support/core_ext/object/deep_dup"
5
+ require "active_model/attribute_set/builder"
6
+ require "active_model/attribute_set/yaml_encoder"
7
+
8
+ module ActiveModel
9
+ class AttributeSet # :nodoc:
10
+ delegate :each_value, :fetch, :except, to: :attributes
11
+
12
+ def initialize(attributes)
13
+ @attributes = attributes
14
+ end
15
+
16
+ def [](name)
17
+ @attributes[name] || default_attribute(name)
18
+ end
19
+
20
+ def []=(name, value)
21
+ @attributes[name] = value
22
+ end
23
+
24
+ def values_before_type_cast
25
+ attributes.transform_values(&:value_before_type_cast)
26
+ end
27
+
28
+ def to_hash
29
+ keys.index_with { |name| self[name].value }
30
+ end
31
+ alias :to_h :to_hash
32
+
33
+ def key?(name)
34
+ attributes.key?(name) && self[name].initialized?
35
+ end
36
+
37
+ def keys
38
+ attributes.each_key.select { |name| self[name].initialized? }
39
+ end
40
+
41
+ def fetch_value(name, &block)
42
+ self[name].value(&block)
43
+ end
44
+
45
+ def write_from_database(name, value)
46
+ @attributes[name] = self[name].with_value_from_database(value)
47
+ end
48
+
49
+ def write_from_user(name, value)
50
+ raise FrozenError, "can't modify frozen attributes" if frozen?
51
+ @attributes[name] = self[name].with_value_from_user(value)
52
+ value
53
+ end
54
+
55
+ def write_cast_value(name, value)
56
+ @attributes[name] = self[name].with_cast_value(value)
57
+ value
58
+ end
59
+
60
+ def freeze
61
+ attributes.freeze
62
+ super
63
+ end
64
+
65
+ def deep_dup
66
+ AttributeSet.new(attributes.deep_dup)
67
+ end
68
+
69
+ def initialize_dup(_)
70
+ @attributes = @attributes.dup
71
+ super
72
+ end
73
+
74
+ def initialize_clone(_)
75
+ @attributes = @attributes.clone
76
+ super
77
+ end
78
+
79
+ def reset(key)
80
+ if key?(key)
81
+ write_from_database(key, nil)
82
+ end
83
+ end
84
+
85
+ def accessed
86
+ attributes.each_key.select { |name| self[name].has_been_read? }
87
+ end
88
+
89
+ def map(&block)
90
+ new_attributes = attributes.transform_values(&block)
91
+ AttributeSet.new(new_attributes)
92
+ end
93
+
94
+ def ==(other)
95
+ attributes == other.attributes
96
+ end
97
+
98
+ protected
99
+ attr_reader :attributes
100
+
101
+ private
102
+ def default_attribute(name)
103
+ Attribute.null(name)
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model/attribute_set"
4
+ require "active_model/attribute/user_provided_default"
5
+
6
+ module ActiveModel
7
+ module Attributes #:nodoc:
8
+ extend ActiveSupport::Concern
9
+ include ActiveModel::AttributeMethods
10
+
11
+ included do
12
+ attribute_method_suffix "="
13
+ class_attribute :attribute_types, :_default_attributes, instance_accessor: false
14
+ self.attribute_types = Hash.new(Type.default_value)
15
+ self._default_attributes = AttributeSet.new({})
16
+ end
17
+
18
+ module ClassMethods
19
+ def attribute(name, type = Type::Value.new, **options)
20
+ name = name.to_s
21
+ if type.is_a?(Symbol)
22
+ type = ActiveModel::Type.lookup(type, **options.except(:default))
23
+ end
24
+ self.attribute_types = attribute_types.merge(name => type)
25
+ define_default_attribute(name, options.fetch(:default, NO_DEFAULT_PROVIDED), type)
26
+ define_attribute_method(name)
27
+ end
28
+
29
+ # Returns an array of attribute names as strings
30
+ #
31
+ # class Person
32
+ # include ActiveModel::Attributes
33
+ #
34
+ # attribute :name, :string
35
+ # attribute :age, :integer
36
+ # end
37
+ #
38
+ # Person.attribute_names
39
+ # # => ["name", "age"]
40
+ def attribute_names
41
+ attribute_types.keys
42
+ end
43
+
44
+ private
45
+ def define_method_attribute=(name, owner:)
46
+ ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
47
+ owner, name, writer: true,
48
+ ) do |temp_method_name, attr_name_expr|
49
+ owner <<
50
+ "def #{temp_method_name}(value)" <<
51
+ " _write_attribute(#{attr_name_expr}, value)" <<
52
+ "end"
53
+ end
54
+ end
55
+
56
+ NO_DEFAULT_PROVIDED = Object.new # :nodoc:
57
+ private_constant :NO_DEFAULT_PROVIDED
58
+
59
+ def define_default_attribute(name, value, type)
60
+ self._default_attributes = _default_attributes.deep_dup
61
+ if value == NO_DEFAULT_PROVIDED
62
+ default_attribute = _default_attributes[name].with_type(type)
63
+ else
64
+ default_attribute = Attribute::UserProvidedDefault.new(
65
+ name,
66
+ value,
67
+ type,
68
+ _default_attributes.fetch(name.to_s) { nil },
69
+ )
70
+ end
71
+ _default_attributes[name] = default_attribute
72
+ end
73
+ end
74
+
75
+ def initialize(*)
76
+ @attributes = self.class._default_attributes.deep_dup
77
+ super
78
+ end
79
+
80
+ def initialize_dup(other) # :nodoc:
81
+ @attributes = @attributes.deep_dup
82
+ super
83
+ end
84
+
85
+ # Returns a hash of all the attributes with their names as keys and the values of the attributes as values.
86
+ #
87
+ # class Person
88
+ # include ActiveModel::Attributes
89
+ #
90
+ # attribute :name, :string
91
+ # attribute :age, :integer
92
+ # end
93
+ #
94
+ # person = Person.new(name: 'Francesco', age: 22)
95
+ # person.attributes
96
+ # # => {"name"=>"Francesco", "age"=>22}
97
+ def attributes
98
+ @attributes.to_hash
99
+ end
100
+
101
+ # Returns an array of attribute names as strings
102
+ #
103
+ # class Person
104
+ # include ActiveModel::Attributes
105
+ #
106
+ # attribute :name, :string
107
+ # attribute :age, :integer
108
+ # end
109
+ #
110
+ # person = Person.new
111
+ # person.attribute_names
112
+ # # => ["name", "age"]
113
+ def attribute_names
114
+ @attributes.keys
115
+ end
116
+
117
+ def freeze
118
+ @attributes = @attributes.clone.freeze unless frozen?
119
+ super
120
+ end
121
+
122
+ private
123
+ def _write_attribute(attr_name, value)
124
+ @attributes.write_from_user(attr_name, value)
125
+ end
126
+ alias :attribute= :_write_attribute
127
+
128
+ def attribute(attr_name)
129
+ @attributes.fetch_value(attr_name)
130
+ end
131
+ end
132
+ end
@@ -1,4 +1,7 @@
1
- require 'active_support/core_ext/array/extract_options'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/array/extract_options"
4
+ require "active_support/core_ext/hash/keys"
2
5
 
3
6
  module ActiveModel
4
7
  # == Active \Model \Callbacks
@@ -6,7 +9,7 @@ module ActiveModel
6
9
  # Provides an interface for any class to have Active Record like callbacks.
7
10
  #
8
11
  # Like the Active Record methods, the callback chain is aborted as soon as
9
- # one of the methods in the chain returns +false+.
12
+ # one of the methods throws +:abort+.
10
13
  #
11
14
  # First, extend ActiveModel::Callbacks from the class you are creating:
12
15
  #
@@ -49,13 +52,16 @@ module ActiveModel
49
52
  # puts 'block successfully called.'
50
53
  # end
51
54
  #
52
- # You can choose not to have all three callbacks by passing a hash to the
55
+ # You can choose to have only specific callbacks by passing a hash to the
53
56
  # +define_model_callbacks+ method.
54
57
  #
55
58
  # define_model_callbacks :create, only: [:after, :before]
56
59
  #
57
60
  # Would only create the +after_create+ and +before_create+ callback methods in
58
61
  # your class.
62
+ #
63
+ # NOTE: Calling the same callback multiple times will overwrite previous callback definitions.
64
+ #
59
65
  module Callbacks
60
66
  def self.extended(base) #:nodoc:
61
67
  base.class_eval do
@@ -98,12 +104,11 @@ module ActiveModel
98
104
  # end
99
105
  # end
100
106
  #
101
- # NOTE: +method_name+ passed to `define_model_callbacks` must not end with
102
- # `!`, `?` or `=`.
107
+ # NOTE: +method_name+ passed to define_model_callbacks must not end with
108
+ # <tt>!</tt>, <tt>?</tt> or <tt>=</tt>.
103
109
  def define_model_callbacks(*callbacks)
104
110
  options = callbacks.extract_options!
105
111
  options = {
106
- terminator: ->(_,result) { result == false },
107
112
  skip_after_callbacks_if_terminated: true,
108
113
  scope: [:kind, :name],
109
114
  only: [:before, :around, :after]
@@ -121,29 +126,30 @@ module ActiveModel
121
126
  end
122
127
 
123
128
  private
124
-
125
- def _define_before_model_callback(klass, callback) #:nodoc:
126
- klass.define_singleton_method("before_#{callback}") do |*args, &block|
127
- set_callback(:"#{callback}", :before, *args, &block)
129
+ def _define_before_model_callback(klass, callback)
130
+ klass.define_singleton_method("before_#{callback}") do |*args, **options, &block|
131
+ options.assert_valid_keys(:if, :unless, :prepend)
132
+ set_callback(:"#{callback}", :before, *args, options, &block)
133
+ end
128
134
  end
129
- end
130
135
 
131
- def _define_around_model_callback(klass, callback) #:nodoc:
132
- klass.define_singleton_method("around_#{callback}") do |*args, &block|
133
- set_callback(:"#{callback}", :around, *args, &block)
136
+ def _define_around_model_callback(klass, callback)
137
+ klass.define_singleton_method("around_#{callback}") do |*args, **options, &block|
138
+ options.assert_valid_keys(:if, :unless, :prepend)
139
+ set_callback(:"#{callback}", :around, *args, options, &block)
140
+ end
134
141
  end
135
- end
136
142
 
137
- def _define_after_model_callback(klass, callback) #:nodoc:
138
- klass.define_singleton_method("after_#{callback}") do |*args, &block|
139
- options = args.extract_options!
140
- options[:prepend] = true
141
- conditional = ActiveSupport::Callbacks::Conditionals::Value.new { |v|
142
- v != false
143
- }
144
- options[:if] = Array(options[:if]) << conditional
145
- set_callback(:"#{callback}", :after, *(args << options), &block)
143
+ def _define_after_model_callback(klass, callback)
144
+ klass.define_singleton_method("after_#{callback}") do |*args, **options, &block|
145
+ options.assert_valid_keys(:if, :unless, :prepend)
146
+ options[:prepend] = true
147
+ conditional = ActiveSupport::Callbacks::Conditionals::Value.new { |v|
148
+ v != false
149
+ }
150
+ options[:if] = Array(options[:if]) << conditional
151
+ set_callback(:"#{callback}", :after, *args, options, &block)
152
+ end
146
153
  end
147
- end
148
154
  end
149
155
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  # == Active \Model \Conversion
3
5
  #
@@ -22,7 +24,7 @@ module ActiveModel
22
24
  module Conversion
23
25
  extend ActiveSupport::Concern
24
26
 
25
- # If your object is already designed to implement all of the Active Model
27
+ # If your object is already designed to implement all of the \Active \Model
26
28
  # you can use the default <tt>:to_model</tt> implementation, which simply
27
29
  # returns +self+.
28
30
  #
@@ -33,22 +35,26 @@ module ActiveModel
33
35
  # person = Person.new
34
36
  # person.to_model == person # => true
35
37
  #
36
- # If your model does not act like an Active Model object, then you should
38
+ # If your model does not act like an \Active \Model object, then you should
37
39
  # define <tt>:to_model</tt> yourself returning a proxy object that wraps
38
- # your object with Active Model compliant methods.
40
+ # your object with \Active \Model compliant methods.
39
41
  def to_model
40
42
  self
41
43
  end
42
44
 
43
- # Returns an Array of all key attributes if any is set, regardless if
44
- # the object is persisted or not. Returns +nil+ if there are no key attributes.
45
+ # Returns an Array of all key attributes if any of the attributes is set, whether or not
46
+ # the object is persisted. Returns +nil+ if there are no key attributes.
45
47
  #
46
48
  # class Person
47
49
  # include ActiveModel::Conversion
48
50
  # attr_accessor :id
51
+ #
52
+ # def initialize(id)
53
+ # @id = id
54
+ # end
49
55
  # end
50
56
  #
51
- # person = Person.create(id: 1)
57
+ # person = Person.new(1)
52
58
  # person.to_key # => [1]
53
59
  def to_key
54
60
  key = respond_to?(:id) && id
@@ -61,15 +67,20 @@ module ActiveModel
61
67
  # class Person
62
68
  # include ActiveModel::Conversion
63
69
  # attr_accessor :id
70
+ #
71
+ # def initialize(id)
72
+ # @id = id
73
+ # end
74
+ #
64
75
  # def persisted?
65
76
  # true
66
77
  # end
67
78
  # end
68
79
  #
69
- # person = Person.create(id: 1)
80
+ # person = Person.new(1)
70
81
  # person.to_param # => "1"
71
82
  def to_param
72
- (persisted? && key = to_key) ? key.join('-') : nil
83
+ (persisted? && key = to_key) ? key.join("-") : nil
73
84
  end
74
85
 
75
86
  # Returns a +string+ identifying the path associated with the object.
@@ -92,7 +103,7 @@ module ActiveModel
92
103
  @_to_partial_path ||= begin
93
104
  element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(name))
94
105
  collection = ActiveSupport::Inflector.tableize(name)
95
- "#{collection}/#{element}".freeze
106
+ "#{collection}/#{element}"
96
107
  end
97
108
  end
98
109
  end