activemodel 4.2.0 → 6.1.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.
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