33# serializable non-activerecord objects.
44module ActiveModelSerializers
55 class Model
6- include ActiveModel ::Model
76 include ActiveModel ::Serializers ::JSON
7+ include ActiveModel ::Validations
8+ include ActiveModel ::Conversion
9+ extend ActiveModel ::Naming
10+ extend ActiveModel ::Translation
11+
12+ class_attribute :attribute_names
13+ self . attribute_names = [ ]
814
915 def self . attributes ( *names )
1016 attr_accessor ( *names )
17+ self . attribute_names = attribute_names | names . map ( &:to_sym )
1118 end
1219
13- attr_reader :attributes , :errors
14-
15- def initialize ( attributes = { } )
16- @attributes = attributes && attributes . symbolize_keys
17- @errors = ActiveModel ::Errors . new ( self )
18- super
19- end
20+ attributes :id , :cache_key , :updated_at
2021
2122 # Defaults to the downcased model name.
2223 def id
23- attributes . fetch ( :id ) { self . class . name . downcase }
24+ @id || self . id = self . class . name . downcase
2425 end
2526
2627 # Defaults to the downcased model name and updated_at
2728 def cache_key
28- attributes . fetch ( : cache_key) { "#{ self . class . name . downcase } /#{ id } -#{ updated_at . strftime ( '%Y%m%d%H%M%S%9N' ) } " }
29+ @cache_key || self . cache_key = "#{ self . class . name . downcase } /#{ id } -#{ updated_at . strftime ( '%Y%m%d%H%M%S%9N' ) } "
2930 end
3031
3132 # Defaults to the time the serializer file was modified.
3233 def updated_at
33- attributes . fetch ( : updated_at) { File . mtime ( __FILE__ ) }
34+ @updated_at || self . updated_at = File . mtime ( __FILE__ )
3435 end
3536
36- def read_attribute_for_serialization ( key )
37- if key == :id || key == 'id'
38- attributes . fetch ( key ) { id }
39- else
40- attributes [ key ]
41- end
37+ attr_reader :errors
38+
39+ def initialize ( attributes = { } )
40+ # attributes = attributes && attributes.symbolize_keys
41+ # attribute_names.each do |attribute_name|
42+ # self.public_send("#{attribute_name}=", attributes[
43+ # end
44+ # attributes.each do |attribute_name, value|
45+ # self.public_send("#{attribute_name}="
46+ #
47+ # end if attributes
48+ assign_attributes ( attributes ) if attributes
49+ @errors = ActiveModel ::Errors . new ( self )
50+ super ( )
51+ end
52+
53+ def attributes
54+ attribute_names . each_with_object ( { } ) do |attribute_name , result |
55+ result [ attribute_name ] = public_send ( attribute_name )
56+ end . with_indifferent_access
4257 end
4358
4459 # The following methods are needed to be minimally implemented for ActiveModel::Errors
@@ -51,5 +66,43 @@ def self.lookup_ancestors
5166 [ self ]
5267 end
5368 # :nocov:
69+
70+ def assign_attributes ( new_attributes )
71+ unless new_attributes . respond_to? ( :stringify_keys )
72+ fail ArgumentError , 'When assigning attributes, you must pass a hash as an argument.'
73+ end
74+ return if new_attributes . blank?
75+
76+ attributes = new_attributes . stringify_keys
77+ _assign_attributes ( attributes )
78+ end
79+
80+ private
81+
82+ def _assign_attributes ( attributes )
83+ attributes . each do |k , v |
84+ _assign_attribute ( k , v )
85+ end
86+ end
87+
88+ def _assign_attribute ( k , v )
89+ fail UnknownAttributeError . new ( self , k ) unless attribute_names . include? ( k . to_sym ) && respond_to? ( "#{ k } =" )
90+ public_send ( "#{ k } =" , v )
91+ end
92+
93+ def persisted?
94+ false
95+ end
96+
97+ # Raised when unknown attributes are supplied via mass assignment.
98+ class UnknownAttributeError < NoMethodError
99+ attr_reader :record , :attribute
100+
101+ def initialize ( record , attribute )
102+ @record = record
103+ @attribute = attribute
104+ super ( "unknown attribute '#{ attribute } ' for #{ @record . class } ." )
105+ end
106+ end
54107 end
55108end
0 commit comments