activemodel 3.0.pre → 3.0.0.rc
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.
- data/CHANGELOG +44 -1
- data/MIT-LICENSE +1 -1
- data/README.rdoc +184 -0
- data/lib/active_model.rb +29 -19
- data/lib/active_model/attribute_methods.rb +167 -46
- data/lib/active_model/callbacks.rb +134 -0
- data/lib/active_model/conversion.rb +41 -1
- data/lib/active_model/deprecated_error_methods.rb +1 -1
- data/lib/active_model/dirty.rb +56 -12
- data/lib/active_model/errors.rb +205 -46
- data/lib/active_model/lint.rb +53 -17
- data/lib/active_model/locale/en.yml +26 -23
- data/lib/active_model/mass_assignment_security.rb +160 -0
- data/lib/active_model/mass_assignment_security/permission_set.rb +40 -0
- data/lib/active_model/mass_assignment_security/sanitizer.rb +23 -0
- data/lib/active_model/naming.rb +70 -5
- data/lib/active_model/observing.rb +40 -16
- data/lib/active_model/railtie.rb +2 -0
- data/lib/active_model/serialization.rb +59 -0
- data/lib/active_model/serializers/json.rb +17 -11
- data/lib/active_model/serializers/xml.rb +66 -123
- data/lib/active_model/test_case.rb +0 -2
- data/lib/active_model/translation.rb +64 -0
- data/lib/active_model/validations.rb +150 -68
- data/lib/active_model/validations/acceptance.rb +53 -33
- data/lib/active_model/validations/callbacks.rb +57 -0
- data/lib/active_model/validations/confirmation.rb +41 -23
- data/lib/active_model/validations/exclusion.rb +18 -13
- data/lib/active_model/validations/format.rb +28 -24
- data/lib/active_model/validations/inclusion.rb +18 -13
- data/lib/active_model/validations/length.rb +67 -65
- data/lib/active_model/validations/numericality.rb +83 -58
- data/lib/active_model/validations/presence.rb +10 -8
- data/lib/active_model/validations/validates.rb +110 -0
- data/lib/active_model/validations/with.rb +90 -23
- data/lib/active_model/validator.rb +186 -0
- data/lib/active_model/version.rb +3 -2
- metadata +79 -20
- data/README +0 -21
- data/lib/active_model/state_machine.rb +0 -70
- data/lib/active_model/state_machine/event.rb +0 -62
- data/lib/active_model/state_machine/machine.rb +0 -75
- data/lib/active_model/state_machine/state.rb +0 -47
- data/lib/active_model/state_machine/state_transition.rb +0 -40
- data/lib/active_model/validations_repair_helper.rb +0 -35
@@ -1,18 +1,16 @@
|
|
1
|
-
require 'observer'
|
2
1
|
require 'singleton'
|
3
2
|
require 'active_support/core_ext/array/wrap'
|
4
3
|
require 'active_support/core_ext/module/aliasing'
|
4
|
+
require 'active_support/core_ext/module/remove_method'
|
5
5
|
require 'active_support/core_ext/string/inflections'
|
6
6
|
|
7
7
|
module ActiveModel
|
8
8
|
module Observing
|
9
9
|
extend ActiveSupport::Concern
|
10
10
|
|
11
|
-
included do
|
12
|
-
extend Observable
|
13
|
-
end
|
14
|
-
|
15
11
|
module ClassMethods
|
12
|
+
# == Active Model Observers Activation
|
13
|
+
#
|
16
14
|
# Activates the observers assigned. Examples:
|
17
15
|
#
|
18
16
|
# # Calls PersonObserver.instance
|
@@ -24,8 +22,9 @@ module ActiveModel
|
|
24
22
|
# # Same as above, just using explicit class references
|
25
23
|
# ActiveRecord::Base.observers = Cacher, GarbageCollector
|
26
24
|
#
|
27
|
-
# Note: Setting this does not instantiate the observers yet.
|
28
|
-
# called during startup, and before
|
25
|
+
# Note: Setting this does not instantiate the observers yet.
|
26
|
+
# +instantiate_observers+ is called during startup, and before
|
27
|
+
# each development request.
|
29
28
|
def observers=(*values)
|
30
29
|
@observers = values.flatten
|
31
30
|
end
|
@@ -40,6 +39,26 @@ module ActiveModel
|
|
40
39
|
observers.each { |o| instantiate_observer(o) }
|
41
40
|
end
|
42
41
|
|
42
|
+
def add_observer(observer)
|
43
|
+
unless observer.respond_to? :update
|
44
|
+
raise ArgumentError, "observer needs to respond to `update'"
|
45
|
+
end
|
46
|
+
@observer_instances ||= []
|
47
|
+
@observer_instances << observer
|
48
|
+
end
|
49
|
+
|
50
|
+
def notify_observers(*arg)
|
51
|
+
if defined? @observer_instances
|
52
|
+
for observer in @observer_instances
|
53
|
+
observer.update(*arg)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def count_observers
|
59
|
+
@observer_instances.size
|
60
|
+
end
|
61
|
+
|
43
62
|
protected
|
44
63
|
def instantiate_observer(observer) #:nodoc:
|
45
64
|
# string/symbol
|
@@ -55,7 +74,6 @@ module ActiveModel
|
|
55
74
|
# Notify observers when the observed class is subclassed.
|
56
75
|
def inherited(subclass)
|
57
76
|
super
|
58
|
-
changed
|
59
77
|
notify_observers :observed_class_inherited, subclass
|
60
78
|
end
|
61
79
|
end
|
@@ -69,11 +87,12 @@ module ActiveModel
|
|
69
87
|
# notify_observers(:after_save)
|
70
88
|
# end
|
71
89
|
def notify_observers(method)
|
72
|
-
self.class.changed
|
73
90
|
self.class.notify_observers(method, self)
|
74
91
|
end
|
75
92
|
end
|
76
93
|
|
94
|
+
# == Active Model Observers
|
95
|
+
#
|
77
96
|
# Observer classes respond to lifecycle callbacks to implement trigger-like
|
78
97
|
# behavior outside the original class. This is a great way to reduce the
|
79
98
|
# clutter that normally comes when the model class is burdened with
|
@@ -102,10 +121,12 @@ module ActiveModel
|
|
102
121
|
#
|
103
122
|
# == Observing a class that can't be inferred
|
104
123
|
#
|
105
|
-
# Observers will by default be mapped to the class with which they share a
|
106
|
-
# be tied to observing Comment, ProductManagerObserver
|
107
|
-
#
|
108
|
-
#
|
124
|
+
# Observers will by default be mapped to the class with which they share a
|
125
|
+
# name. So CommentObserver will be tied to observing Comment, ProductManagerObserver
|
126
|
+
# to ProductManager, and so on. If you want to name your observer differently than
|
127
|
+
# the class you're interested in observing, you can use the Observer.observe class
|
128
|
+
# method which takes either the concrete class (Product) or a symbol for that
|
129
|
+
# class (:product):
|
109
130
|
#
|
110
131
|
# class AuditObserver < ActiveModel::Observer
|
111
132
|
# observe :account
|
@@ -115,7 +136,8 @@ module ActiveModel
|
|
115
136
|
# end
|
116
137
|
# end
|
117
138
|
#
|
118
|
-
# If the audit observer needs to watch more than one kind of object, this can be
|
139
|
+
# If the audit observer needs to watch more than one kind of object, this can be
|
140
|
+
# specified with multiple arguments:
|
119
141
|
#
|
120
142
|
# class AuditObserver < ActiveModel::Observer
|
121
143
|
# observe :account, :balance
|
@@ -125,7 +147,8 @@ module ActiveModel
|
|
125
147
|
# end
|
126
148
|
# end
|
127
149
|
#
|
128
|
-
# The AuditObserver will now act on both updates to Account and Balance by treating
|
150
|
+
# The AuditObserver will now act on both updates to Account and Balance by treating
|
151
|
+
# them both as records.
|
129
152
|
#
|
130
153
|
class Observer
|
131
154
|
include Singleton
|
@@ -135,6 +158,7 @@ module ActiveModel
|
|
135
158
|
def observe(*models)
|
136
159
|
models.flatten!
|
137
160
|
models.collect! { |model| model.respond_to?(:to_sym) ? model.to_s.camelize.constantize : model }
|
161
|
+
remove_possible_method(:observed_classes)
|
138
162
|
define_method(:observed_classes) { models }
|
139
163
|
end
|
140
164
|
|
@@ -144,7 +168,7 @@ module ActiveModel
|
|
144
168
|
#
|
145
169
|
# class AuditObserver < ActiveModel::Observer
|
146
170
|
# def self.observed_classes
|
147
|
-
# [
|
171
|
+
# [Account, Balance]
|
148
172
|
# end
|
149
173
|
# end
|
150
174
|
def observed_classes
|
@@ -2,6 +2,65 @@ require 'active_support/core_ext/hash/except'
|
|
2
2
|
require 'active_support/core_ext/hash/slice'
|
3
3
|
|
4
4
|
module ActiveModel
|
5
|
+
# == Active Model Serialization
|
6
|
+
#
|
7
|
+
# Provides a basic serialization to a serializable_hash for your object.
|
8
|
+
#
|
9
|
+
# A minimal implementation could be:
|
10
|
+
#
|
11
|
+
# class Person
|
12
|
+
#
|
13
|
+
# include ActiveModel::Serialization
|
14
|
+
#
|
15
|
+
# attr_accessor :name
|
16
|
+
#
|
17
|
+
# def attributes
|
18
|
+
# @attributes ||= {'name' => 'nil'}
|
19
|
+
# end
|
20
|
+
#
|
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
|
+
# You need to declare some sort of attributes hash which contains the attributes
|
31
|
+
# you want to serialize and their current value.
|
32
|
+
#
|
33
|
+
# Most of the time though, you will want to include the JSON or XML
|
34
|
+
# serializations. Both of these modules automatically include the
|
35
|
+
# ActiveModel::Serialization module, so there is no need to explicitly
|
36
|
+
# include it.
|
37
|
+
#
|
38
|
+
# So a minimal implementation including XML and JSON would be:
|
39
|
+
#
|
40
|
+
# class Person
|
41
|
+
#
|
42
|
+
# include ActiveModel::Serializers::JSON
|
43
|
+
# include ActiveModel::Serializers::Xml
|
44
|
+
#
|
45
|
+
# attr_accessor :name
|
46
|
+
#
|
47
|
+
# def attributes
|
48
|
+
# @attributes ||= {'name' => 'nil'}
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
# Which would provide you with:
|
54
|
+
#
|
55
|
+
# person = Person.new
|
56
|
+
# person.serializable_hash # => {"name"=>nil}
|
57
|
+
# person.to_json # => "{\"name\":null}"
|
58
|
+
# person.to_xml # => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<serial-person...
|
59
|
+
#
|
60
|
+
# person.name = "Bob"
|
61
|
+
# person.serializable_hash # => {"name"=>"Bob"}
|
62
|
+
# person.to_json # => "{\"name\":\"Bob\"}"
|
63
|
+
# person.to_xml # => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<serial-person...
|
5
64
|
module Serialization
|
6
65
|
def serializable_hash(options = nil)
|
7
66
|
options ||= {}
|
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'active_support/json'
|
2
|
-
require 'active_support/core_ext/class/
|
2
|
+
require 'active_support/core_ext/class/attribute'
|
3
3
|
|
4
4
|
module ActiveModel
|
5
|
+
# == Active Model JSON Serializer
|
5
6
|
module Serializers
|
6
7
|
module JSON
|
7
8
|
extend ActiveSupport::Concern
|
@@ -10,19 +11,18 @@ module ActiveModel
|
|
10
11
|
included do
|
11
12
|
extend ActiveModel::Naming
|
12
13
|
|
13
|
-
|
14
|
+
class_attribute :include_root_in_json
|
15
|
+
self.include_root_in_json = true
|
14
16
|
end
|
15
17
|
|
16
|
-
# Returns a JSON string representing the model. Some configuration
|
17
|
-
#
|
18
|
+
# Returns a JSON string representing the model. Some configuration can be
|
19
|
+
# passed through +options+.
|
18
20
|
#
|
19
|
-
# The option <tt>
|
20
|
-
# top-level behavior of to_json
|
21
|
-
# <tt>
|
22
|
-
# to_json will emit a single root node named after the object's type. For example:
|
21
|
+
# The option <tt>ActiveModel::Base.include_root_in_json</tt> controls the
|
22
|
+
# top-level behavior of <tt>to_json</tt>. It is <tt>true</tt> by default. When it is <tt>true</tt>,
|
23
|
+
# <tt>to_json</tt> will emit a single root node named after the object's type. For example:
|
23
24
|
#
|
24
25
|
# konata = User.find(1)
|
25
|
-
# ActiveRecord::Base.include_root_in_json = true
|
26
26
|
# konata.to_json
|
27
27
|
# # => { "user": {"id": 1, "name": "Konata Izumi", "age": 16,
|
28
28
|
# "created_at": "2006/08/01", "awesome": true} }
|
@@ -81,7 +81,11 @@ module ActiveModel
|
|
81
81
|
# "title": "So I was thinking"}]}
|
82
82
|
def encode_json(encoder)
|
83
83
|
hash = serializable_hash(encoder.options)
|
84
|
-
|
84
|
+
if include_root_in_json
|
85
|
+
custom_root = encoder.options && encoder.options[:root]
|
86
|
+
hash = { custom_root || self.class.model_name.element => hash }
|
87
|
+
end
|
88
|
+
|
85
89
|
ActiveSupport::JSON.encode(hash)
|
86
90
|
end
|
87
91
|
|
@@ -90,7 +94,9 @@ module ActiveModel
|
|
90
94
|
end
|
91
95
|
|
92
96
|
def from_json(json)
|
93
|
-
|
97
|
+
hash = ActiveSupport::JSON.decode(json)
|
98
|
+
hash = hash.values.first if include_root_in_json
|
99
|
+
self.attributes = hash
|
94
100
|
self
|
95
101
|
end
|
96
102
|
end
|
@@ -1,7 +1,11 @@
|
|
1
|
+
require 'active_support/core_ext/array/wrap'
|
1
2
|
require 'active_support/core_ext/class/attribute_accessors'
|
3
|
+
require 'active_support/core_ext/array/conversions'
|
2
4
|
require 'active_support/core_ext/hash/conversions'
|
5
|
+
require 'active_support/core_ext/hash/slice'
|
3
6
|
|
4
7
|
module ActiveModel
|
8
|
+
# == Active Model XML Serializer
|
5
9
|
module Serializers
|
6
10
|
module Xml
|
7
11
|
extend ActiveSupport::Concern
|
@@ -11,68 +15,31 @@ module ActiveModel
|
|
11
15
|
class Attribute #:nodoc:
|
12
16
|
attr_reader :name, :value, :type
|
13
17
|
|
14
|
-
def initialize(name, serializable)
|
18
|
+
def initialize(name, serializable, raw_value=nil)
|
15
19
|
@name, @serializable = name, serializable
|
20
|
+
@value = value || @serializable.send(name)
|
16
21
|
@type = compute_type
|
17
|
-
@value = compute_value
|
18
22
|
end
|
19
23
|
|
20
|
-
|
21
|
-
# does not need to be escaped, as <tt>tag!</tt> escapes all values
|
22
|
-
# to ensure that valid XML is generated. For known binary
|
23
|
-
# values, it is at least an order of magnitude faster to
|
24
|
-
# Base64 encode binary values and directly put them in the
|
25
|
-
# output XML than to pass the original value or the Base64
|
26
|
-
# encoded value to the <tt>tag!</tt> method. It definitely makes
|
27
|
-
# no sense to Base64 encode the value and then give it to
|
28
|
-
# <tt>tag!</tt>, since that just adds additional overhead.
|
29
|
-
def needs_encoding?
|
30
|
-
![ :binary, :date, :datetime, :boolean, :float, :integer ].include?(type)
|
31
|
-
end
|
32
|
-
|
33
|
-
def decorations(include_types = true)
|
24
|
+
def decorations
|
34
25
|
decorations = {}
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
end
|
39
|
-
|
40
|
-
if include_types && type != :string
|
41
|
-
decorations[:type] = type
|
42
|
-
end
|
43
|
-
|
44
|
-
if value.nil?
|
45
|
-
decorations[:nil] = true
|
46
|
-
end
|
47
|
-
|
26
|
+
decorations[:encoding] = 'base64' if type == :binary
|
27
|
+
decorations[:type] = type unless type == :string
|
28
|
+
decorations[:nil] = true if value.nil?
|
48
29
|
decorations
|
49
30
|
end
|
50
31
|
|
51
|
-
|
52
|
-
def compute_type
|
53
|
-
value = @serializable.send(name)
|
54
|
-
type = Hash::XML_TYPE_NAMES[value.class.name]
|
55
|
-
type ||= :string if value.respond_to?(:to_str)
|
56
|
-
type ||= :yaml
|
57
|
-
type
|
58
|
-
end
|
59
|
-
|
60
|
-
def compute_value
|
61
|
-
value = @serializable.send(name)
|
32
|
+
protected
|
62
33
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
34
|
+
def compute_type
|
35
|
+
type = ActiveSupport::XmlMini::TYPE_NAMES[value.class.name]
|
36
|
+
type ||= :string if value.respond_to?(:to_str)
|
37
|
+
type ||= :yaml
|
38
|
+
type
|
39
|
+
end
|
69
40
|
end
|
70
41
|
|
71
42
|
class MethodAttribute < Attribute #:nodoc:
|
72
|
-
protected
|
73
|
-
def compute_type
|
74
|
-
Hash::XML_TYPE_NAMES[@serializable.send(name).class.name] || :string
|
75
|
-
end
|
76
43
|
end
|
77
44
|
|
78
45
|
attr_reader :options
|
@@ -85,112 +52,88 @@ module ActiveModel
|
|
85
52
|
@options[:except] = Array.wrap(@options[:except]).map { |n| n.to_s }
|
86
53
|
end
|
87
54
|
|
88
|
-
# To replicate the behavior in ActiveRecord#attributes,
|
89
|
-
#
|
55
|
+
# To replicate the behavior in ActiveRecord#attributes, <tt>:except</tt>
|
56
|
+
# takes precedence over <tt>:only</tt>. If <tt>:only</tt> is not set
|
90
57
|
# for a N level model but is set for the N+1 level models,
|
91
58
|
# then because <tt>:except</tt> is set to a default value, the second
|
92
59
|
# level model can have both <tt>:except</tt> and <tt>:only</tt> set. So if
|
93
60
|
# <tt>:only</tt> is set, always delete <tt>:except</tt>.
|
94
|
-
def
|
95
|
-
|
96
|
-
|
61
|
+
def attributes_hash
|
62
|
+
attributes = @serializable.attributes
|
97
63
|
if options[:only].any?
|
98
|
-
|
64
|
+
attributes.slice(*options[:only])
|
99
65
|
elsif options[:except].any?
|
100
|
-
|
66
|
+
attributes.except(*options[:except])
|
67
|
+
else
|
68
|
+
attributes
|
101
69
|
end
|
102
|
-
|
103
|
-
attribute_names
|
104
70
|
end
|
105
71
|
|
106
72
|
def serializable_attributes
|
107
|
-
|
73
|
+
attributes_hash.map do |name, value|
|
74
|
+
self.class::Attribute.new(name, @serializable, value)
|
75
|
+
end
|
108
76
|
end
|
109
77
|
|
110
|
-
def
|
111
|
-
Array(options[:methods]).inject([]) do |methods, name|
|
112
|
-
methods << MethodAttribute.new(name.to_s, @serializable) if @serializable.respond_to?(name.to_s)
|
78
|
+
def serializable_methods
|
79
|
+
Array.wrap(options[:methods]).inject([]) do |methods, name|
|
80
|
+
methods << self.class::MethodAttribute.new(name.to_s, @serializable) if @serializable.respond_to?(name.to_s)
|
113
81
|
methods
|
114
82
|
end
|
115
83
|
end
|
116
84
|
|
117
85
|
def serialize
|
118
|
-
|
119
|
-
|
120
|
-
if options[:namespace]
|
121
|
-
args << {:xmlns => options[:namespace]}
|
122
|
-
end
|
86
|
+
require 'builder' unless defined? ::Builder
|
123
87
|
|
124
|
-
|
125
|
-
|
126
|
-
end
|
88
|
+
options[:indent] ||= 2
|
89
|
+
options[:builder] ||= ::Builder::XmlMarkup.new(:indent => options[:indent])
|
127
90
|
|
128
|
-
builder
|
129
|
-
|
130
|
-
procs = options.delete(:procs)
|
131
|
-
options[:procs] = procs
|
132
|
-
add_procs
|
133
|
-
yield builder if block_given?
|
134
|
-
end
|
135
|
-
end
|
91
|
+
@builder = options[:builder]
|
92
|
+
@builder.instruct! unless options[:skip_instruct]
|
136
93
|
|
137
|
-
|
138
|
-
|
139
|
-
@builder ||= begin
|
140
|
-
require 'builder' unless defined? ::Builder
|
141
|
-
options[:indent] ||= 2
|
142
|
-
builder = options[:builder] ||= ::Builder::XmlMarkup.new(:indent => options[:indent])
|
94
|
+
root = (options[:root] || @serializable.class.model_name.element).to_s
|
95
|
+
root = ActiveSupport::XmlMini.rename_key(root, options)
|
143
96
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
end
|
148
|
-
|
149
|
-
builder
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
def root
|
154
|
-
root = (options[:root] || @serializable.class.model_name.singular).to_s
|
155
|
-
reformat_name(root)
|
156
|
-
end
|
97
|
+
args = [root]
|
98
|
+
args << {:xmlns => options[:namespace]} if options[:namespace]
|
99
|
+
args << {:type => options[:type]} if options[:type] && !options[:skip_types]
|
157
100
|
|
158
|
-
|
159
|
-
|
101
|
+
@builder.tag!(*args) do
|
102
|
+
add_attributes_and_methods
|
103
|
+
add_extra_behavior
|
104
|
+
add_procs
|
105
|
+
yield @builder if block_given?
|
160
106
|
end
|
107
|
+
end
|
161
108
|
|
162
|
-
|
163
|
-
options.has_key?(:camelize) && options[:camelize]
|
164
|
-
end
|
109
|
+
private
|
165
110
|
|
166
|
-
|
167
|
-
|
168
|
-
dasherize? ? name.dasherize : name
|
169
|
-
end
|
111
|
+
def add_extra_behavior
|
112
|
+
end
|
170
113
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
attribute.decorations(!options[:skip_types])
|
177
|
-
)
|
178
|
-
end
|
114
|
+
def add_attributes_and_methods
|
115
|
+
(serializable_attributes + serializable_methods).each do |attribute|
|
116
|
+
key = ActiveSupport::XmlMini.rename_key(attribute.name, options)
|
117
|
+
ActiveSupport::XmlMini.to_tag(key, attribute.value,
|
118
|
+
options.merge(attribute.decorations))
|
179
119
|
end
|
120
|
+
end
|
180
121
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
end
|
122
|
+
def add_procs
|
123
|
+
if procs = options.delete(:procs)
|
124
|
+
Array.wrap(procs).each do |proc|
|
125
|
+
if proc.arity == 1
|
126
|
+
proc.call(options)
|
127
|
+
else
|
128
|
+
proc.call(options, @serializable)
|
189
129
|
end
|
190
130
|
end
|
191
131
|
end
|
132
|
+
end
|
192
133
|
end
|
193
134
|
|
135
|
+
# Returns XML representing the model. Configuration can be
|
136
|
+
# passed through +options+.
|
194
137
|
def to_xml(options = {}, &block)
|
195
138
|
Serializer.new(self, options).serialize(&block)
|
196
139
|
end
|