activemodel 3.2.22.5 → 4.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +85 -64
- data/MIT-LICENSE +1 -1
- data/README.rdoc +61 -24
- data/lib/active_model.rb +21 -11
- data/lib/active_model/attribute_methods.rb +150 -125
- data/lib/active_model/callbacks.rb +49 -34
- data/lib/active_model/conversion.rb +39 -19
- data/lib/active_model/deprecated_mass_assignment_security.rb +21 -0
- data/lib/active_model/dirty.rb +48 -32
- data/lib/active_model/errors.rb +176 -88
- data/lib/active_model/forbidden_attributes_protection.rb +27 -0
- data/lib/active_model/lint.rb +42 -55
- data/lib/active_model/locale/en.yml +3 -1
- data/lib/active_model/model.rb +97 -0
- data/lib/active_model/naming.rb +191 -51
- data/lib/active_model/railtie.rb +11 -1
- data/lib/active_model/secure_password.rb +55 -25
- data/lib/active_model/serialization.rb +51 -27
- data/lib/active_model/serializers/json.rb +83 -46
- data/lib/active_model/serializers/xml.rb +46 -12
- data/lib/active_model/test_case.rb +0 -12
- data/lib/active_model/translation.rb +9 -10
- data/lib/active_model/validations.rb +154 -52
- data/lib/active_model/validations/absence.rb +31 -0
- data/lib/active_model/validations/acceptance.rb +10 -22
- data/lib/active_model/validations/callbacks.rb +78 -25
- data/lib/active_model/validations/clusivity.rb +41 -0
- data/lib/active_model/validations/confirmation.rb +13 -23
- data/lib/active_model/validations/exclusion.rb +26 -55
- data/lib/active_model/validations/format.rb +44 -34
- data/lib/active_model/validations/inclusion.rb +22 -52
- data/lib/active_model/validations/length.rb +48 -49
- data/lib/active_model/validations/numericality.rb +30 -32
- data/lib/active_model/validations/presence.rb +12 -22
- data/lib/active_model/validations/validates.rb +68 -36
- data/lib/active_model/validations/with.rb +28 -23
- data/lib/active_model/validator.rb +22 -22
- data/lib/active_model/version.rb +4 -4
- metadata +23 -24
- data/lib/active_model/mass_assignment_security.rb +0 -237
- data/lib/active_model/mass_assignment_security/permission_set.rb +0 -40
- data/lib/active_model/mass_assignment_security/sanitizer.rb +0 -59
- data/lib/active_model/observer_array.rb +0 -147
- data/lib/active_model/observing.rb +0 -252
data/lib/active_model/railtie.rb
CHANGED
@@ -1,2 +1,12 @@
|
|
1
1
|
require "active_model"
|
2
|
-
require "rails"
|
2
|
+
require "rails"
|
3
|
+
|
4
|
+
module ActiveModel
|
5
|
+
class Railtie < Rails::Railtie # :nodoc:
|
6
|
+
config.eager_load_namespaces << ActiveModel
|
7
|
+
|
8
|
+
initializer "active_model.secure_password" do
|
9
|
+
ActiveModel::SecurePassword.min_cost = Rails.env.test?
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -2,15 +2,23 @@ module ActiveModel
|
|
2
2
|
module SecurePassword
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
|
+
class << self; attr_accessor :min_cost; end
|
6
|
+
self.min_cost = false
|
7
|
+
|
5
8
|
module ClassMethods
|
6
9
|
# Adds methods to set and authenticate against a BCrypt password.
|
7
10
|
# This mechanism requires you to have a password_digest attribute.
|
8
11
|
#
|
9
|
-
# Validations for presence of password, confirmation of password
|
10
|
-
# a
|
11
|
-
#
|
12
|
+
# Validations for presence of password on create, confirmation of password
|
13
|
+
# (using a +password_confirmation+ attribute) are automatically added. If
|
14
|
+
# you wish to turn off validations, pass <tt>validations: false</tt> as an
|
15
|
+
# argument. You can add more validations by hand if need be.
|
16
|
+
#
|
17
|
+
# If you don't need the confirmation validation, just don't set any
|
18
|
+
# value to the password_confirmation attribute and the the validation
|
19
|
+
# will not be triggered.
|
12
20
|
#
|
13
|
-
# You need to add bcrypt-ruby (~> 3.0.0) to Gemfile to use has_secure_password:
|
21
|
+
# You need to add bcrypt-ruby (~> 3.0.0) to Gemfile to use #has_secure_password:
|
14
22
|
#
|
15
23
|
# gem 'bcrypt-ruby', '~> 3.0.0'
|
16
24
|
#
|
@@ -21,31 +29,36 @@ module ActiveModel
|
|
21
29
|
# has_secure_password
|
22
30
|
# end
|
23
31
|
#
|
24
|
-
# user = User.new(:
|
32
|
+
# user = User.new(name: 'david', password: '', password_confirmation: 'nomatch')
|
25
33
|
# user.save # => false, password required
|
26
|
-
# user.password =
|
34
|
+
# user.password = 'mUc3m00RsqyRe'
|
27
35
|
# user.save # => false, confirmation doesn't match
|
28
|
-
# user.password_confirmation =
|
36
|
+
# user.password_confirmation = 'mUc3m00RsqyRe'
|
29
37
|
# user.save # => true
|
30
|
-
# user.authenticate(
|
31
|
-
# user.authenticate(
|
32
|
-
# User.find_by_name(
|
33
|
-
# User.find_by_name(
|
34
|
-
def has_secure_password
|
38
|
+
# user.authenticate('notright') # => false
|
39
|
+
# user.authenticate('mUc3m00RsqyRe') # => user
|
40
|
+
# User.find_by_name('david').try(:authenticate, 'notright') # => false
|
41
|
+
# User.find_by_name('david').try(:authenticate, 'mUc3m00RsqyRe') # => user
|
42
|
+
def has_secure_password(options = {})
|
35
43
|
# Load bcrypt-ruby only when has_secure_password is used.
|
36
|
-
# This is to avoid ActiveModel (and by extension the entire framework)
|
44
|
+
# This is to avoid ActiveModel (and by extension the entire framework)
|
45
|
+
# being dependent on a binary library.
|
37
46
|
gem 'bcrypt-ruby', '~> 3.0.0'
|
38
47
|
require 'bcrypt'
|
39
48
|
|
40
49
|
attr_reader :password
|
41
50
|
|
42
|
-
|
43
|
-
|
51
|
+
if options.fetch(:validations, true)
|
52
|
+
validates_confirmation_of :password
|
53
|
+
validates_presence_of :password, :on => :create
|
54
|
+
|
55
|
+
before_create { raise "Password digest missing on new record" if password_digest.blank? }
|
56
|
+
end
|
44
57
|
|
45
58
|
include InstanceMethodsOnActivation
|
46
59
|
|
47
60
|
if respond_to?(:attributes_protected_by_default)
|
48
|
-
def self.attributes_protected_by_default
|
61
|
+
def self.attributes_protected_by_default #:nodoc:
|
49
62
|
super + ['password_digest']
|
50
63
|
end
|
51
64
|
end
|
@@ -53,20 +66,37 @@ module ActiveModel
|
|
53
66
|
end
|
54
67
|
|
55
68
|
module InstanceMethodsOnActivation
|
56
|
-
# Returns self if the password is correct, otherwise false
|
69
|
+
# Returns +self+ if the password is correct, otherwise +false+.
|
70
|
+
#
|
71
|
+
# class User < ActiveRecord::Base
|
72
|
+
# has_secure_password validations: false
|
73
|
+
# end
|
74
|
+
#
|
75
|
+
# user = User.new(name: 'david', password: 'mUc3m00RsqyRe')
|
76
|
+
# user.save
|
77
|
+
# user.authenticate('notright') # => false
|
78
|
+
# user.authenticate('mUc3m00RsqyRe') # => user
|
57
79
|
def authenticate(unencrypted_password)
|
58
|
-
|
59
|
-
self
|
60
|
-
else
|
61
|
-
false
|
62
|
-
end
|
80
|
+
BCrypt::Password.new(password_digest) == unencrypted_password && self
|
63
81
|
end
|
64
82
|
|
65
|
-
# Encrypts the password into the password_digest attribute
|
83
|
+
# Encrypts the password into the +password_digest+ attribute, only if the
|
84
|
+
# new password is not blank.
|
85
|
+
#
|
86
|
+
# class User < ActiveRecord::Base
|
87
|
+
# has_secure_password validations: false
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# user = User.new
|
91
|
+
# user.password = nil
|
92
|
+
# user.password_digest # => nil
|
93
|
+
# user.password = 'mUc3m00RsqyRe'
|
94
|
+
# user.password_digest # => "$2a$10$4LEA7r4YmNHtvlAvHhsYAeZmk/xeUVtMTYqwIvYY76EW5GUqDiP4."
|
66
95
|
def password=(unencrypted_password)
|
67
|
-
@password = unencrypted_password
|
68
96
|
unless unencrypted_password.blank?
|
69
|
-
|
97
|
+
@password = unencrypted_password
|
98
|
+
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine::DEFAULT_COST
|
99
|
+
self.password_digest = BCrypt::Password.create(unencrypted_password, cost: cost)
|
70
100
|
end
|
71
101
|
end
|
72
102
|
end
|
@@ -1,25 +1,21 @@
|
|
1
1
|
require 'active_support/core_ext/hash/except'
|
2
2
|
require 'active_support/core_ext/hash/slice'
|
3
|
-
require 'active_support/core_ext/array/wrap'
|
4
|
-
|
5
3
|
|
6
4
|
module ActiveModel
|
7
|
-
# == Active Model Serialization
|
5
|
+
# == Active \Model \Serialization
|
8
6
|
#
|
9
7
|
# Provides a basic serialization to a serializable_hash for your object.
|
10
8
|
#
|
11
9
|
# A minimal implementation could be:
|
12
10
|
#
|
13
11
|
# class Person
|
14
|
-
#
|
15
12
|
# include ActiveModel::Serialization
|
16
13
|
#
|
17
14
|
# attr_accessor :name
|
18
15
|
#
|
19
16
|
# def attributes
|
20
|
-
# {'name' =>
|
17
|
+
# {'name' => nil}
|
21
18
|
# end
|
22
|
-
#
|
23
19
|
# end
|
24
20
|
#
|
25
21
|
# Which would provide you with:
|
@@ -29,27 +25,28 @@ module ActiveModel
|
|
29
25
|
# person.name = "Bob"
|
30
26
|
# person.serializable_hash # => {"name"=>"Bob"}
|
31
27
|
#
|
32
|
-
# You need to declare
|
33
|
-
#
|
28
|
+
# You need to declare an attributes hash which contains the attributes you
|
29
|
+
# want to serialize. Attributes must be strings, not symbols. When called,
|
30
|
+
# serializable hash will use instance methods that match the name of the
|
31
|
+
# attributes hash's keys. In order to override this behavior, take a look at
|
32
|
+
# the private method +read_attribute_for_serialization+.
|
34
33
|
#
|
35
34
|
# Most of the time though, you will want to include the JSON or XML
|
36
35
|
# serializations. Both of these modules automatically include the
|
37
|
-
# ActiveModel::Serialization module, so there is no need to
|
38
|
-
# include it.
|
36
|
+
# <tt>ActiveModel::Serialization</tt> module, so there is no need to
|
37
|
+
# explicitly include it.
|
39
38
|
#
|
40
|
-
#
|
39
|
+
# A minimal implementation including XML and JSON would be:
|
41
40
|
#
|
42
41
|
# class Person
|
43
|
-
#
|
44
42
|
# include ActiveModel::Serializers::JSON
|
45
43
|
# include ActiveModel::Serializers::Xml
|
46
44
|
#
|
47
45
|
# attr_accessor :name
|
48
46
|
#
|
49
47
|
# def attributes
|
50
|
-
# {'name' =>
|
48
|
+
# {'name' => nil}
|
51
49
|
# end
|
52
|
-
#
|
53
50
|
# end
|
54
51
|
#
|
55
52
|
# Which would provide you with:
|
@@ -66,27 +63,55 @@ module ActiveModel
|
|
66
63
|
# person.to_json # => "{\"name\":\"Bob\"}"
|
67
64
|
# person.to_xml # => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<serial-person...
|
68
65
|
#
|
69
|
-
# Valid options are <tt>:only</tt>, <tt>:except</tt
|
66
|
+
# Valid options are <tt>:only</tt>, <tt>:except</tt>, <tt>:methods</tt> and
|
67
|
+
# <tt>:include</tt>. The following are all valid examples:
|
68
|
+
#
|
69
|
+
# person.serializable_hash(only: 'name')
|
70
|
+
# person.serializable_hash(include: :address)
|
71
|
+
# person.serializable_hash(include: { address: { only: 'city' }})
|
70
72
|
module Serialization
|
73
|
+
# Returns a serialized hash of your object.
|
74
|
+
#
|
75
|
+
# class Person
|
76
|
+
# include ActiveModel::Serialization
|
77
|
+
#
|
78
|
+
# attr_accessor :name, :age
|
79
|
+
#
|
80
|
+
# def attributes
|
81
|
+
# {'name' => nil, 'age' => nil}
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
# def capitalized_name
|
85
|
+
# name.capitalize
|
86
|
+
# end
|
87
|
+
# end
|
88
|
+
#
|
89
|
+
# person = Person.new
|
90
|
+
# person.name = 'bob'
|
91
|
+
# person.age = 22
|
92
|
+
# person.serializable_hash # => {"name"=>"bob", "age"=>22}
|
93
|
+
# person.serializable_hash(only: :name) # => {"name"=>"bob"}
|
94
|
+
# person.serializable_hash(except: :name) # => {"age"=>22}
|
95
|
+
# person.serializable_hash(methods: :capitalized_name)
|
96
|
+
# # => {"name"=>"bob", "age"=>22, "capitalized_name"=>"Bob"}
|
71
97
|
def serializable_hash(options = nil)
|
72
98
|
options ||= {}
|
73
99
|
|
74
|
-
attribute_names = attributes.keys
|
100
|
+
attribute_names = attributes.keys
|
75
101
|
if only = options[:only]
|
76
|
-
attribute_names &= Array
|
102
|
+
attribute_names &= Array(only).map(&:to_s)
|
77
103
|
elsif except = options[:except]
|
78
|
-
attribute_names -= Array
|
104
|
+
attribute_names -= Array(except).map(&:to_s)
|
79
105
|
end
|
80
106
|
|
81
107
|
hash = {}
|
82
108
|
attribute_names.each { |n| hash[n] = read_attribute_for_serialization(n) }
|
83
109
|
|
84
|
-
|
85
|
-
method_names.each { |n| hash[n] = send(n) }
|
110
|
+
Array(options[:methods]).each { |m| hash[m.to_s] = send(m) if respond_to?(m) }
|
86
111
|
|
87
112
|
serializable_add_includes(options) do |association, records, opts|
|
88
|
-
hash[association] = if records.
|
89
|
-
records.map { |a| a.serializable_hash(opts) }
|
113
|
+
hash[association.to_s] = if records.respond_to?(:to_ary)
|
114
|
+
records.to_ary.map { |a| a.serializable_hash(opts) }
|
90
115
|
else
|
91
116
|
records.serializable_hash(opts)
|
92
117
|
end
|
@@ -113,7 +138,6 @@ module ActiveModel
|
|
113
138
|
# @data[key]
|
114
139
|
# end
|
115
140
|
# end
|
116
|
-
#
|
117
141
|
alias :read_attribute_for_serialization :send
|
118
142
|
|
119
143
|
# Add associations specified via the <tt>:include</tt> option.
|
@@ -123,13 +147,13 @@ module ActiveModel
|
|
123
147
|
# +records+ - the association record(s) to be serialized
|
124
148
|
# +opts+ - options for the association records
|
125
149
|
def serializable_add_includes(options = {}) #:nodoc:
|
126
|
-
return unless
|
150
|
+
return unless includes = options[:include]
|
127
151
|
|
128
|
-
unless
|
129
|
-
|
152
|
+
unless includes.is_a?(Hash)
|
153
|
+
includes = Hash[Array(includes).map { |n| n.is_a?(Hash) ? n.to_a.first : [n, {}] }]
|
130
154
|
end
|
131
155
|
|
132
|
-
|
156
|
+
includes.each do |association, opts|
|
133
157
|
if records = send(association)
|
134
158
|
yield association, records, opts
|
135
159
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'active_support/json'
|
2
|
-
require 'active_support/core_ext/class/attribute'
|
3
2
|
|
4
3
|
module ActiveModel
|
5
4
|
module Serializers
|
@@ -12,83 +11,87 @@ module ActiveModel
|
|
12
11
|
extend ActiveModel::Naming
|
13
12
|
|
14
13
|
class_attribute :include_root_in_json
|
15
|
-
self.include_root_in_json =
|
14
|
+
self.include_root_in_json = false
|
16
15
|
end
|
17
16
|
|
18
17
|
# Returns a hash representing the model. Some configuration can be
|
19
18
|
# passed through +options+.
|
20
19
|
#
|
21
20
|
# The option <tt>include_root_in_json</tt> controls the top-level behavior
|
22
|
-
# of +as_json+. If true
|
23
|
-
#
|
21
|
+
# of +as_json+. If +true+, +as_json+ will emit a single root node named
|
22
|
+
# after the object's type. The default value for <tt>include_root_in_json</tt>
|
23
|
+
# option is +false+.
|
24
24
|
#
|
25
25
|
# user = User.find(1)
|
26
26
|
# user.as_json
|
27
|
-
# # => { "
|
28
|
-
#
|
27
|
+
# # => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
|
28
|
+
# # "created_at" => "2006/08/01", "awesome" => true}
|
29
|
+
#
|
30
|
+
# ActiveRecord::Base.include_root_in_json = true
|
29
31
|
#
|
30
|
-
# ActiveRecord::Base.include_root_in_json = false
|
31
32
|
# user.as_json
|
32
|
-
# # => {"id"
|
33
|
-
#
|
33
|
+
# # => { "user" => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
|
34
|
+
# # "created_at" => "2006/08/01", "awesome" => true } }
|
34
35
|
#
|
35
|
-
# This behavior can also be achieved by setting the <tt>:root</tt> option
|
36
|
+
# This behavior can also be achieved by setting the <tt>:root</tt> option
|
37
|
+
# to +true+ as in:
|
36
38
|
#
|
37
39
|
# user = User.find(1)
|
38
|
-
# user.as_json(root:
|
39
|
-
# # =>
|
40
|
-
#
|
41
|
-
#
|
42
|
-
# The remainder of the examples in this section assume include_root_in_json is set to
|
43
|
-
# <tt>false</tt>.
|
40
|
+
# user.as_json(root: true)
|
41
|
+
# # => { "user" => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
|
42
|
+
# # "created_at" => "2006/08/01", "awesome" => true } }
|
44
43
|
#
|
45
44
|
# Without any +options+, the returned Hash will include all the model's
|
46
|
-
# attributes.
|
45
|
+
# attributes.
|
47
46
|
#
|
48
47
|
# user = User.find(1)
|
49
48
|
# user.as_json
|
50
|
-
# # => {"id"
|
51
|
-
#
|
49
|
+
# # => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
|
50
|
+
# # "created_at" => "2006/08/01", "awesome" => true}
|
52
51
|
#
|
53
|
-
# The <tt>:only</tt> and <tt>:except</tt> options can be used to limit
|
54
|
-
# included, and work similar to the +attributes+ method.
|
52
|
+
# The <tt>:only</tt> and <tt>:except</tt> options can be used to limit
|
53
|
+
# the attributes included, and work similar to the +attributes+ method.
|
55
54
|
#
|
56
|
-
# user.as_json(:
|
57
|
-
# # => {"id"
|
55
|
+
# user.as_json(only: [:id, :name])
|
56
|
+
# # => { "id" => 1, "name" => "Konata Izumi" }
|
58
57
|
#
|
59
|
-
# user.as_json(:
|
60
|
-
# # => {"name"
|
58
|
+
# user.as_json(except: [:id, :created_at, :age])
|
59
|
+
# # => { "name" => "Konata Izumi", "awesome" => true }
|
61
60
|
#
|
62
61
|
# To include the result of some method calls on the model use <tt>:methods</tt>:
|
63
62
|
#
|
64
|
-
# user.as_json(:
|
65
|
-
# # => {"id"
|
66
|
-
#
|
67
|
-
#
|
63
|
+
# user.as_json(methods: :permalink)
|
64
|
+
# # => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
|
65
|
+
# # "created_at" => "2006/08/01", "awesome" => true,
|
66
|
+
# # "permalink" => "1-konata-izumi" }
|
68
67
|
#
|
69
68
|
# To include associations use <tt>:include</tt>:
|
70
69
|
#
|
71
|
-
# user.as_json(:
|
72
|
-
# # => {"id"
|
73
|
-
#
|
74
|
-
#
|
75
|
-
# {"id"
|
70
|
+
# user.as_json(include: :posts)
|
71
|
+
# # => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
|
72
|
+
# # "created_at" => "2006/08/01", "awesome" => true,
|
73
|
+
# # "posts" => [ { "id" => 1, "author_id" => 1, "title" => "Welcome to the weblog" },
|
74
|
+
# # { "id" => 2, "author_id" => 1, "title" => "So I was thinking" } ] }
|
76
75
|
#
|
77
76
|
# Second level and higher order associations work as well:
|
78
77
|
#
|
79
|
-
# user.as_json(:
|
80
|
-
#
|
81
|
-
#
|
82
|
-
#
|
83
|
-
# # => {"id"
|
84
|
-
#
|
85
|
-
#
|
86
|
-
#
|
87
|
-
# {"comments"
|
88
|
-
#
|
78
|
+
# user.as_json(include: { posts: {
|
79
|
+
# include: { comments: {
|
80
|
+
# only: :body } },
|
81
|
+
# only: :title } })
|
82
|
+
# # => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
|
83
|
+
# # "created_at" => "2006/08/01", "awesome" => true,
|
84
|
+
# # "posts" => [ { "comments" => [ { "body" => "1st post!" }, { "body" => "Second!" } ],
|
85
|
+
# # "title" => "Welcome to the weblog" },
|
86
|
+
# # { "comments" => [ { "body" => "Don't think too hard" } ],
|
87
|
+
# # "title" => "So I was thinking" } ] }
|
89
88
|
def as_json(options = nil)
|
90
|
-
root =
|
91
|
-
|
89
|
+
root = if options && options.key?(:root)
|
90
|
+
options[:root]
|
91
|
+
else
|
92
|
+
include_root_in_json
|
93
|
+
end
|
94
|
+
|
92
95
|
if root
|
93
96
|
root = self.class.model_name.element if root == true
|
94
97
|
{ root => serializable_hash(options) }
|
@@ -97,6 +100,40 @@ module ActiveModel
|
|
97
100
|
end
|
98
101
|
end
|
99
102
|
|
103
|
+
# Sets the model +attributes+ from a JSON string. Returns +self+.
|
104
|
+
#
|
105
|
+
# class Person
|
106
|
+
# include ActiveModel::Serializers::JSON
|
107
|
+
#
|
108
|
+
# attr_accessor :name, :age, :awesome
|
109
|
+
#
|
110
|
+
# def attributes=(hash)
|
111
|
+
# hash.each do |key, value|
|
112
|
+
# instance_variable_set("@#{key}", value)
|
113
|
+
# end
|
114
|
+
# end
|
115
|
+
#
|
116
|
+
# def attributes
|
117
|
+
# instance_values
|
118
|
+
# end
|
119
|
+
# end
|
120
|
+
#
|
121
|
+
# json = { name: 'bob', age: 22, awesome:true }.to_json
|
122
|
+
# person = Person.new
|
123
|
+
# person.from_json(json) # => #<Person:0x007fec5e7a0088 @age=22, @awesome=true, @name="bob">
|
124
|
+
# person.name # => "bob"
|
125
|
+
# person.age # => 22
|
126
|
+
# person.awesome # => true
|
127
|
+
#
|
128
|
+
# The default value for +include_root+ is +false+. You can change it to
|
129
|
+
# +true+ if the given JSON string includes a single root node.
|
130
|
+
#
|
131
|
+
# json = { person: { name: 'bob', age: 22, awesome:true } }.to_json
|
132
|
+
# person = Person.new
|
133
|
+
# person.from_json(json) # => #<Person:0x007fec5e7a0088 @age=22, @awesome=true, @name="bob">
|
134
|
+
# person.name # => "bob"
|
135
|
+
# person.age # => 22
|
136
|
+
# person.awesome # => true
|
100
137
|
def from_json(json, include_root=include_root_in_json)
|
101
138
|
hash = ActiveSupport::JSON.decode(json)
|
102
139
|
hash = hash.values.first if include_root
|