activemodel 5.2.3
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +114 -0
- data/MIT-LICENSE +21 -0
- data/README.rdoc +264 -0
- data/lib/active_model.rb +77 -0
- data/lib/active_model/attribute.rb +248 -0
- data/lib/active_model/attribute/user_provided_default.rb +52 -0
- data/lib/active_model/attribute_assignment.rb +57 -0
- data/lib/active_model/attribute_methods.rb +478 -0
- data/lib/active_model/attribute_mutation_tracker.rb +124 -0
- data/lib/active_model/attribute_set.rb +114 -0
- data/lib/active_model/attribute_set/builder.rb +126 -0
- data/lib/active_model/attribute_set/yaml_encoder.rb +41 -0
- data/lib/active_model/attributes.rb +111 -0
- data/lib/active_model/callbacks.rb +153 -0
- data/lib/active_model/conversion.rb +111 -0
- data/lib/active_model/dirty.rb +343 -0
- data/lib/active_model/errors.rb +517 -0
- data/lib/active_model/forbidden_attributes_protection.rb +31 -0
- data/lib/active_model/gem_version.rb +17 -0
- data/lib/active_model/lint.rb +118 -0
- data/lib/active_model/locale/en.yml +36 -0
- data/lib/active_model/model.rb +99 -0
- data/lib/active_model/naming.rb +318 -0
- data/lib/active_model/railtie.rb +14 -0
- data/lib/active_model/secure_password.rb +129 -0
- data/lib/active_model/serialization.rb +192 -0
- data/lib/active_model/serializers/json.rb +146 -0
- data/lib/active_model/translation.rb +70 -0
- data/lib/active_model/type.rb +53 -0
- data/lib/active_model/type/big_integer.rb +15 -0
- data/lib/active_model/type/binary.rb +52 -0
- data/lib/active_model/type/boolean.rb +38 -0
- data/lib/active_model/type/date.rb +57 -0
- data/lib/active_model/type/date_time.rb +51 -0
- data/lib/active_model/type/decimal.rb +70 -0
- data/lib/active_model/type/float.rb +36 -0
- data/lib/active_model/type/helpers.rb +7 -0
- data/lib/active_model/type/helpers/accepts_multiparameter_time.rb +41 -0
- data/lib/active_model/type/helpers/mutable.rb +20 -0
- data/lib/active_model/type/helpers/numeric.rb +37 -0
- data/lib/active_model/type/helpers/time_value.rb +68 -0
- data/lib/active_model/type/helpers/timezone.rb +19 -0
- data/lib/active_model/type/immutable_string.rb +32 -0
- data/lib/active_model/type/integer.rb +70 -0
- data/lib/active_model/type/registry.rb +70 -0
- data/lib/active_model/type/string.rb +26 -0
- data/lib/active_model/type/time.rb +51 -0
- data/lib/active_model/type/value.rb +126 -0
- data/lib/active_model/validations.rb +439 -0
- data/lib/active_model/validations/absence.rb +33 -0
- data/lib/active_model/validations/acceptance.rb +106 -0
- data/lib/active_model/validations/callbacks.rb +122 -0
- data/lib/active_model/validations/clusivity.rb +54 -0
- data/lib/active_model/validations/confirmation.rb +80 -0
- data/lib/active_model/validations/exclusion.rb +49 -0
- data/lib/active_model/validations/format.rb +114 -0
- data/lib/active_model/validations/helper_methods.rb +15 -0
- data/lib/active_model/validations/inclusion.rb +47 -0
- data/lib/active_model/validations/length.rb +129 -0
- data/lib/active_model/validations/numericality.rb +189 -0
- data/lib/active_model/validations/presence.rb +39 -0
- data/lib/active_model/validations/validates.rb +174 -0
- data/lib/active_model/validations/with.rb +147 -0
- data/lib/active_model/validator.rb +183 -0
- data/lib/active_model/version.rb +10 -0
- metadata +125 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_model"
|
4
|
+
require "rails"
|
5
|
+
|
6
|
+
module ActiveModel
|
7
|
+
class Railtie < Rails::Railtie # :nodoc:
|
8
|
+
config.eager_load_namespaces << ActiveModel
|
9
|
+
|
10
|
+
initializer "active_model.secure_password" do
|
11
|
+
ActiveModel::SecurePassword.min_cost = Rails.env.test?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveModel
|
4
|
+
module SecurePassword
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
# BCrypt hash function can handle maximum 72 bytes, and if we pass
|
8
|
+
# password of length more than 72 bytes it ignores extra characters.
|
9
|
+
# Hence need to put a restriction on password length.
|
10
|
+
MAX_PASSWORD_LENGTH_ALLOWED = 72
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_accessor :min_cost # :nodoc:
|
14
|
+
end
|
15
|
+
self.min_cost = false
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
# Adds methods to set and authenticate against a BCrypt password.
|
19
|
+
# This mechanism requires you to have a +password_digest+ attribute.
|
20
|
+
#
|
21
|
+
# The following validations are added automatically:
|
22
|
+
# * Password must be present on creation
|
23
|
+
# * Password length should be less than or equal to 72 bytes
|
24
|
+
# * Confirmation of password (using a +password_confirmation+ attribute)
|
25
|
+
#
|
26
|
+
# If password confirmation validation is not needed, simply leave out the
|
27
|
+
# value for +password_confirmation+ (i.e. don't provide a form field for
|
28
|
+
# it). When this attribute has a +nil+ value, the validation will not be
|
29
|
+
# triggered.
|
30
|
+
#
|
31
|
+
# For further customizability, it is possible to suppress the default
|
32
|
+
# validations by passing <tt>validations: false</tt> as an argument.
|
33
|
+
#
|
34
|
+
# Add bcrypt (~> 3.1.7) to Gemfile to use #has_secure_password:
|
35
|
+
#
|
36
|
+
# gem 'bcrypt', '~> 3.1.7'
|
37
|
+
#
|
38
|
+
# Example using Active Record (which automatically includes ActiveModel::SecurePassword):
|
39
|
+
#
|
40
|
+
# # Schema: User(name:string, password_digest:string)
|
41
|
+
# class User < ActiveRecord::Base
|
42
|
+
# has_secure_password
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# user = User.new(name: 'david', password: '', password_confirmation: 'nomatch')
|
46
|
+
# user.save # => false, password required
|
47
|
+
# user.password = 'mUc3m00RsqyRe'
|
48
|
+
# user.save # => false, confirmation doesn't match
|
49
|
+
# user.password_confirmation = 'mUc3m00RsqyRe'
|
50
|
+
# user.save # => true
|
51
|
+
# user.authenticate('notright') # => false
|
52
|
+
# user.authenticate('mUc3m00RsqyRe') # => user
|
53
|
+
# User.find_by(name: 'david').try(:authenticate, 'notright') # => false
|
54
|
+
# User.find_by(name: 'david').try(:authenticate, 'mUc3m00RsqyRe') # => user
|
55
|
+
def has_secure_password(options = {})
|
56
|
+
# Load bcrypt gem only when has_secure_password is used.
|
57
|
+
# This is to avoid ActiveModel (and by extension the entire framework)
|
58
|
+
# being dependent on a binary library.
|
59
|
+
begin
|
60
|
+
require "bcrypt"
|
61
|
+
rescue LoadError
|
62
|
+
$stderr.puts "You don't have bcrypt installed in your application. Please add it to your Gemfile and run bundle install"
|
63
|
+
raise
|
64
|
+
end
|
65
|
+
|
66
|
+
include InstanceMethodsOnActivation
|
67
|
+
|
68
|
+
if options.fetch(:validations, true)
|
69
|
+
include ActiveModel::Validations
|
70
|
+
|
71
|
+
# This ensures the model has a password by checking whether the password_digest
|
72
|
+
# is present, so that this works with both new and existing records. However,
|
73
|
+
# when there is an error, the message is added to the password attribute instead
|
74
|
+
# so that the error message will make sense to the end-user.
|
75
|
+
validate do |record|
|
76
|
+
record.errors.add(:password, :blank) unless record.password_digest.present?
|
77
|
+
end
|
78
|
+
|
79
|
+
validates_length_of :password, maximum: ActiveModel::SecurePassword::MAX_PASSWORD_LENGTH_ALLOWED
|
80
|
+
validates_confirmation_of :password, allow_blank: true
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
module InstanceMethodsOnActivation
|
86
|
+
# Returns +self+ if the password is correct, otherwise +false+.
|
87
|
+
#
|
88
|
+
# class User < ActiveRecord::Base
|
89
|
+
# has_secure_password validations: false
|
90
|
+
# end
|
91
|
+
#
|
92
|
+
# user = User.new(name: 'david', password: 'mUc3m00RsqyRe')
|
93
|
+
# user.save
|
94
|
+
# user.authenticate('notright') # => false
|
95
|
+
# user.authenticate('mUc3m00RsqyRe') # => user
|
96
|
+
def authenticate(unencrypted_password)
|
97
|
+
BCrypt::Password.new(password_digest).is_password?(unencrypted_password) && self
|
98
|
+
end
|
99
|
+
|
100
|
+
attr_reader :password
|
101
|
+
|
102
|
+
# Encrypts the password into the +password_digest+ attribute, only if the
|
103
|
+
# new password is not empty.
|
104
|
+
#
|
105
|
+
# class User < ActiveRecord::Base
|
106
|
+
# has_secure_password validations: false
|
107
|
+
# end
|
108
|
+
#
|
109
|
+
# user = User.new
|
110
|
+
# user.password = nil
|
111
|
+
# user.password_digest # => nil
|
112
|
+
# user.password = 'mUc3m00RsqyRe'
|
113
|
+
# user.password_digest # => "$2a$10$4LEA7r4YmNHtvlAvHhsYAeZmk/xeUVtMTYqwIvYY76EW5GUqDiP4."
|
114
|
+
def password=(unencrypted_password)
|
115
|
+
if unencrypted_password.nil?
|
116
|
+
self.password_digest = nil
|
117
|
+
elsif !unencrypted_password.empty?
|
118
|
+
@password = unencrypted_password
|
119
|
+
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost
|
120
|
+
self.password_digest = BCrypt::Password.create(unencrypted_password, cost: cost)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def password_confirmation=(unencrypted_password)
|
125
|
+
@password_confirmation = unencrypted_password
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/hash/except"
|
4
|
+
require "active_support/core_ext/hash/slice"
|
5
|
+
|
6
|
+
module ActiveModel
|
7
|
+
# == Active \Model \Serialization
|
8
|
+
#
|
9
|
+
# Provides a basic serialization to a serializable_hash for your objects.
|
10
|
+
#
|
11
|
+
# A minimal implementation could be:
|
12
|
+
#
|
13
|
+
# class Person
|
14
|
+
# include ActiveModel::Serialization
|
15
|
+
#
|
16
|
+
# attr_accessor :name
|
17
|
+
#
|
18
|
+
# def attributes
|
19
|
+
# {'name' => nil}
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# Which would provide you with:
|
24
|
+
#
|
25
|
+
# person = Person.new
|
26
|
+
# person.serializable_hash # => {"name"=>nil}
|
27
|
+
# person.name = "Bob"
|
28
|
+
# person.serializable_hash # => {"name"=>"Bob"}
|
29
|
+
#
|
30
|
+
# An +attributes+ hash must be defined and should contain any attributes you
|
31
|
+
# need to be serialized. Attributes must be strings, not symbols.
|
32
|
+
# When called, serializable hash will use instance methods that match the name
|
33
|
+
# of the attributes hash's keys. In order to override this behavior, take a look
|
34
|
+
# at the private method +read_attribute_for_serialization+.
|
35
|
+
#
|
36
|
+
# ActiveModel::Serializers::JSON module automatically includes
|
37
|
+
# the <tt>ActiveModel::Serialization</tt> module, so there is no need to
|
38
|
+
# explicitly include <tt>ActiveModel::Serialization</tt>.
|
39
|
+
#
|
40
|
+
# A minimal implementation including JSON would be:
|
41
|
+
#
|
42
|
+
# class Person
|
43
|
+
# include ActiveModel::Serializers::JSON
|
44
|
+
#
|
45
|
+
# attr_accessor :name
|
46
|
+
#
|
47
|
+
# def attributes
|
48
|
+
# {'name' => nil}
|
49
|
+
# end
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# Which would provide you with:
|
53
|
+
#
|
54
|
+
# person = Person.new
|
55
|
+
# person.serializable_hash # => {"name"=>nil}
|
56
|
+
# person.as_json # => {"name"=>nil}
|
57
|
+
# person.to_json # => "{\"name\":null}"
|
58
|
+
#
|
59
|
+
# person.name = "Bob"
|
60
|
+
# person.serializable_hash # => {"name"=>"Bob"}
|
61
|
+
# person.as_json # => {"name"=>"Bob"}
|
62
|
+
# person.to_json # => "{\"name\":\"Bob\"}"
|
63
|
+
#
|
64
|
+
# Valid options are <tt>:only</tt>, <tt>:except</tt>, <tt>:methods</tt> and
|
65
|
+
# <tt>:include</tt>. The following are all valid examples:
|
66
|
+
#
|
67
|
+
# person.serializable_hash(only: 'name')
|
68
|
+
# person.serializable_hash(include: :address)
|
69
|
+
# person.serializable_hash(include: { address: { only: 'city' }})
|
70
|
+
module Serialization
|
71
|
+
# Returns a serialized hash of your object.
|
72
|
+
#
|
73
|
+
# class Person
|
74
|
+
# include ActiveModel::Serialization
|
75
|
+
#
|
76
|
+
# attr_accessor :name, :age
|
77
|
+
#
|
78
|
+
# def attributes
|
79
|
+
# {'name' => nil, 'age' => nil}
|
80
|
+
# end
|
81
|
+
#
|
82
|
+
# def capitalized_name
|
83
|
+
# name.capitalize
|
84
|
+
# end
|
85
|
+
# end
|
86
|
+
#
|
87
|
+
# person = Person.new
|
88
|
+
# person.name = 'bob'
|
89
|
+
# person.age = 22
|
90
|
+
# person.serializable_hash # => {"name"=>"bob", "age"=>22}
|
91
|
+
# person.serializable_hash(only: :name) # => {"name"=>"bob"}
|
92
|
+
# person.serializable_hash(except: :name) # => {"age"=>22}
|
93
|
+
# person.serializable_hash(methods: :capitalized_name)
|
94
|
+
# # => {"name"=>"bob", "age"=>22, "capitalized_name"=>"Bob"}
|
95
|
+
#
|
96
|
+
# Example with <tt>:include</tt> option
|
97
|
+
#
|
98
|
+
# class User
|
99
|
+
# include ActiveModel::Serializers::JSON
|
100
|
+
# attr_accessor :name, :notes # Emulate has_many :notes
|
101
|
+
# def attributes
|
102
|
+
# {'name' => nil}
|
103
|
+
# end
|
104
|
+
# end
|
105
|
+
#
|
106
|
+
# class Note
|
107
|
+
# include ActiveModel::Serializers::JSON
|
108
|
+
# attr_accessor :title, :text
|
109
|
+
# def attributes
|
110
|
+
# {'title' => nil, 'text' => nil}
|
111
|
+
# end
|
112
|
+
# end
|
113
|
+
#
|
114
|
+
# note = Note.new
|
115
|
+
# note.title = 'Battle of Austerlitz'
|
116
|
+
# note.text = 'Some text here'
|
117
|
+
#
|
118
|
+
# user = User.new
|
119
|
+
# user.name = 'Napoleon'
|
120
|
+
# user.notes = [note]
|
121
|
+
#
|
122
|
+
# user.serializable_hash
|
123
|
+
# # => {"name" => "Napoleon"}
|
124
|
+
# user.serializable_hash(include: { notes: { only: 'title' }})
|
125
|
+
# # => {"name" => "Napoleon", "notes" => [{"title"=>"Battle of Austerlitz"}]}
|
126
|
+
def serializable_hash(options = nil)
|
127
|
+
options ||= {}
|
128
|
+
|
129
|
+
attribute_names = attributes.keys
|
130
|
+
if only = options[:only]
|
131
|
+
attribute_names &= Array(only).map(&:to_s)
|
132
|
+
elsif except = options[:except]
|
133
|
+
attribute_names -= Array(except).map(&:to_s)
|
134
|
+
end
|
135
|
+
|
136
|
+
hash = {}
|
137
|
+
attribute_names.each { |n| hash[n] = read_attribute_for_serialization(n) }
|
138
|
+
|
139
|
+
Array(options[:methods]).each { |m| hash[m.to_s] = send(m) }
|
140
|
+
|
141
|
+
serializable_add_includes(options) do |association, records, opts|
|
142
|
+
hash[association.to_s] = if records.respond_to?(:to_ary)
|
143
|
+
records.to_ary.map { |a| a.serializable_hash(opts) }
|
144
|
+
else
|
145
|
+
records.serializable_hash(opts)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
hash
|
150
|
+
end
|
151
|
+
|
152
|
+
private
|
153
|
+
|
154
|
+
# Hook method defining how an attribute value should be retrieved for
|
155
|
+
# serialization. By default this is assumed to be an instance named after
|
156
|
+
# the attribute. Override this method in subclasses should you need to
|
157
|
+
# retrieve the value for a given attribute differently:
|
158
|
+
#
|
159
|
+
# class MyClass
|
160
|
+
# include ActiveModel::Serialization
|
161
|
+
#
|
162
|
+
# def initialize(data = {})
|
163
|
+
# @data = data
|
164
|
+
# end
|
165
|
+
#
|
166
|
+
# def read_attribute_for_serialization(key)
|
167
|
+
# @data[key]
|
168
|
+
# end
|
169
|
+
# end
|
170
|
+
alias :read_attribute_for_serialization :send
|
171
|
+
|
172
|
+
# Add associations specified via the <tt>:include</tt> option.
|
173
|
+
#
|
174
|
+
# Expects a block that takes as arguments:
|
175
|
+
# +association+ - name of the association
|
176
|
+
# +records+ - the association record(s) to be serialized
|
177
|
+
# +opts+ - options for the association records
|
178
|
+
def serializable_add_includes(options = {}) #:nodoc:
|
179
|
+
return unless includes = options[:include]
|
180
|
+
|
181
|
+
unless includes.is_a?(Hash)
|
182
|
+
includes = Hash[Array(includes).flat_map { |n| n.is_a?(Hash) ? n.to_a : [[n, {}]] }]
|
183
|
+
end
|
184
|
+
|
185
|
+
includes.each do |association, opts|
|
186
|
+
if records = send(association)
|
187
|
+
yield association, records, opts
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/json"
|
4
|
+
|
5
|
+
module ActiveModel
|
6
|
+
module Serializers
|
7
|
+
# == Active \Model \JSON \Serializer
|
8
|
+
module JSON
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
include ActiveModel::Serialization
|
11
|
+
|
12
|
+
included do
|
13
|
+
extend ActiveModel::Naming
|
14
|
+
|
15
|
+
class_attribute :include_root_in_json, instance_writer: false, default: false
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns a hash representing the model. Some configuration can be
|
19
|
+
# passed through +options+.
|
20
|
+
#
|
21
|
+
# The option <tt>include_root_in_json</tt> controls the top-level behavior
|
22
|
+
# of +as_json+. If +true+, +as_json+ will emit a single root node named
|
23
|
+
# after the object's type. The default value for <tt>include_root_in_json</tt>
|
24
|
+
# option is +false+.
|
25
|
+
#
|
26
|
+
# user = User.find(1)
|
27
|
+
# user.as_json
|
28
|
+
# # => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
|
29
|
+
# # "created_at" => "2006/08/01", "awesome" => true}
|
30
|
+
#
|
31
|
+
# ActiveRecord::Base.include_root_in_json = true
|
32
|
+
#
|
33
|
+
# user.as_json
|
34
|
+
# # => { "user" => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
|
35
|
+
# # "created_at" => "2006/08/01", "awesome" => true } }
|
36
|
+
#
|
37
|
+
# This behavior can also be achieved by setting the <tt>:root</tt> option
|
38
|
+
# to +true+ as in:
|
39
|
+
#
|
40
|
+
# user = User.find(1)
|
41
|
+
# user.as_json(root: true)
|
42
|
+
# # => { "user" => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
|
43
|
+
# # "created_at" => "2006/08/01", "awesome" => true } }
|
44
|
+
#
|
45
|
+
# Without any +options+, the returned Hash will include all the model's
|
46
|
+
# attributes.
|
47
|
+
#
|
48
|
+
# user = User.find(1)
|
49
|
+
# user.as_json
|
50
|
+
# # => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
|
51
|
+
# # "created_at" => "2006/08/01", "awesome" => true}
|
52
|
+
#
|
53
|
+
# The <tt>:only</tt> and <tt>:except</tt> options can be used to limit
|
54
|
+
# the attributes included, and work similar to the +attributes+ method.
|
55
|
+
#
|
56
|
+
# user.as_json(only: [:id, :name])
|
57
|
+
# # => { "id" => 1, "name" => "Konata Izumi" }
|
58
|
+
#
|
59
|
+
# user.as_json(except: [:id, :created_at, :age])
|
60
|
+
# # => { "name" => "Konata Izumi", "awesome" => true }
|
61
|
+
#
|
62
|
+
# To include the result of some method calls on the model use <tt>:methods</tt>:
|
63
|
+
#
|
64
|
+
# user.as_json(methods: :permalink)
|
65
|
+
# # => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
|
66
|
+
# # "created_at" => "2006/08/01", "awesome" => true,
|
67
|
+
# # "permalink" => "1-konata-izumi" }
|
68
|
+
#
|
69
|
+
# To include associations use <tt>:include</tt>:
|
70
|
+
#
|
71
|
+
# user.as_json(include: :posts)
|
72
|
+
# # => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
|
73
|
+
# # "created_at" => "2006/08/01", "awesome" => true,
|
74
|
+
# # "posts" => [ { "id" => 1, "author_id" => 1, "title" => "Welcome to the weblog" },
|
75
|
+
# # { "id" => 2, "author_id" => 1, "title" => "So I was thinking" } ] }
|
76
|
+
#
|
77
|
+
# Second level and higher order associations work as well:
|
78
|
+
#
|
79
|
+
# user.as_json(include: { posts: {
|
80
|
+
# include: { comments: {
|
81
|
+
# only: :body } },
|
82
|
+
# only: :title } })
|
83
|
+
# # => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
|
84
|
+
# # "created_at" => "2006/08/01", "awesome" => true,
|
85
|
+
# # "posts" => [ { "comments" => [ { "body" => "1st post!" }, { "body" => "Second!" } ],
|
86
|
+
# # "title" => "Welcome to the weblog" },
|
87
|
+
# # { "comments" => [ { "body" => "Don't think too hard" } ],
|
88
|
+
# # "title" => "So I was thinking" } ] }
|
89
|
+
def as_json(options = nil)
|
90
|
+
root = if options && options.key?(:root)
|
91
|
+
options[:root]
|
92
|
+
else
|
93
|
+
include_root_in_json
|
94
|
+
end
|
95
|
+
|
96
|
+
if root
|
97
|
+
root = model_name.element if root == true
|
98
|
+
{ root => serializable_hash(options) }
|
99
|
+
else
|
100
|
+
serializable_hash(options)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Sets the model +attributes+ from a JSON string. Returns +self+.
|
105
|
+
#
|
106
|
+
# class Person
|
107
|
+
# include ActiveModel::Serializers::JSON
|
108
|
+
#
|
109
|
+
# attr_accessor :name, :age, :awesome
|
110
|
+
#
|
111
|
+
# def attributes=(hash)
|
112
|
+
# hash.each do |key, value|
|
113
|
+
# send("#{key}=", value)
|
114
|
+
# end
|
115
|
+
# end
|
116
|
+
#
|
117
|
+
# def attributes
|
118
|
+
# instance_values
|
119
|
+
# end
|
120
|
+
# end
|
121
|
+
#
|
122
|
+
# json = { name: 'bob', age: 22, awesome:true }.to_json
|
123
|
+
# person = Person.new
|
124
|
+
# person.from_json(json) # => #<Person:0x007fec5e7a0088 @age=22, @awesome=true, @name="bob">
|
125
|
+
# person.name # => "bob"
|
126
|
+
# person.age # => 22
|
127
|
+
# person.awesome # => true
|
128
|
+
#
|
129
|
+
# The default value for +include_root+ is +false+. You can change it to
|
130
|
+
# +true+ if the given JSON string includes a single root node.
|
131
|
+
#
|
132
|
+
# json = { person: { name: 'bob', age: 22, awesome:true } }.to_json
|
133
|
+
# person = Person.new
|
134
|
+
# person.from_json(json, true) # => #<Person:0x007fec5e7a0088 @age=22, @awesome=true, @name="bob">
|
135
|
+
# person.name # => "bob"
|
136
|
+
# person.age # => 22
|
137
|
+
# person.awesome # => true
|
138
|
+
def from_json(json, include_root = include_root_in_json)
|
139
|
+
hash = ActiveSupport::JSON.decode(json)
|
140
|
+
hash = hash.values.first if include_root
|
141
|
+
self.attributes = hash
|
142
|
+
self
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|