activeresource-five 5.0.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.
- checksums.yaml +7 -0
- data/README.rdoc +249 -0
- data/lib/active_resource.rb +44 -0
- data/lib/active_resource/associations.rb +175 -0
- data/lib/active_resource/associations/builder/association.rb +32 -0
- data/lib/active_resource/associations/builder/belongs_to.rb +14 -0
- data/lib/active_resource/associations/builder/has_many.rb +12 -0
- data/lib/active_resource/associations/builder/has_one.rb +12 -0
- data/lib/active_resource/base.rb +1626 -0
- data/lib/active_resource/callbacks.rb +20 -0
- data/lib/active_resource/collection.rb +92 -0
- data/lib/active_resource/connection.rb +299 -0
- data/lib/active_resource/custom_methods.rb +127 -0
- data/lib/active_resource/exceptions.rb +82 -0
- data/lib/active_resource/formats.rb +22 -0
- data/lib/active_resource/formats/json_format.rb +25 -0
- data/lib/active_resource/formats/xml_format.rb +25 -0
- data/lib/active_resource/http_mock.rb +375 -0
- data/lib/active_resource/log_subscriber.rb +15 -0
- data/lib/active_resource/observing.rb +0 -0
- data/lib/active_resource/railtie.rb +15 -0
- data/lib/active_resource/reflection.rb +77 -0
- data/lib/active_resource/schema.rb +57 -0
- data/lib/active_resource/singleton.rb +114 -0
- data/lib/active_resource/threadsafe_attributes.rb +65 -0
- data/lib/active_resource/validations.rb +174 -0
- data/lib/active_resource/version.rb +10 -0
- data/lib/activeresource.rb +1 -0
- metadata +156 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
module ActiveResource
|
2
|
+
class LogSubscriber < ActiveSupport::LogSubscriber
|
3
|
+
def request(event)
|
4
|
+
result = event.payload[:result]
|
5
|
+
info "#{event.payload[:method].to_s.upcase} #{event.payload[:request_uri]}"
|
6
|
+
info "--> %d %s %d (%.1fms)" % [result.code, result.message, result.body.to_s.length, event.duration]
|
7
|
+
end
|
8
|
+
|
9
|
+
def logger
|
10
|
+
ActiveResource::Base.logger
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
ActiveResource::LogSubscriber.attach_to :active_resource
|
File without changes
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "active_resource"
|
2
|
+
require "rails"
|
3
|
+
|
4
|
+
module ActiveResource
|
5
|
+
class Railtie < Rails::Railtie
|
6
|
+
config.active_resource = ActiveSupport::OrderedOptions.new
|
7
|
+
|
8
|
+
initializer "active_resource.set_configs" do |app|
|
9
|
+
app.config.active_resource.each do |k,v|
|
10
|
+
ActiveResource::Base.send "#{k}=", v
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'active_support/core_ext/class/attribute'
|
2
|
+
require 'active_support/core_ext/module/deprecation'
|
3
|
+
|
4
|
+
module ActiveResource
|
5
|
+
# = Active Resource reflection
|
6
|
+
#
|
7
|
+
# Associations in ActiveResource would be used to resolve nested attributes
|
8
|
+
# in a response with correct classes.
|
9
|
+
# Now they could be specified over Associations with the options :class_name
|
10
|
+
module Reflection # :nodoc:
|
11
|
+
extend ActiveSupport::Concern
|
12
|
+
|
13
|
+
included do
|
14
|
+
class_attribute :reflections
|
15
|
+
self.reflections = {}
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
def create_reflection(macro, name, options)
|
20
|
+
reflection = AssociationReflection.new(macro, name, options)
|
21
|
+
self.reflections = self.reflections.merge(name => reflection)
|
22
|
+
reflection
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
class AssociationReflection
|
28
|
+
|
29
|
+
def initialize(macro, name, options)
|
30
|
+
@macro, @name, @options = macro, name, options
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns the name of the macro.
|
34
|
+
#
|
35
|
+
# <tt>has_many :clients</tt> returns <tt>:clients</tt>
|
36
|
+
attr_reader :name
|
37
|
+
|
38
|
+
# Returns the macro type.
|
39
|
+
#
|
40
|
+
# <tt>has_many :clients</tt> returns <tt>:has_many</tt>
|
41
|
+
attr_reader :macro
|
42
|
+
|
43
|
+
# Returns the hash of options used for the macro.
|
44
|
+
#
|
45
|
+
# <tt>has_many :clients</tt> returns +{}+
|
46
|
+
attr_reader :options
|
47
|
+
|
48
|
+
# Returns the class for the macro.
|
49
|
+
#
|
50
|
+
# <tt>has_many :clients</tt> returns the Client class
|
51
|
+
def klass
|
52
|
+
@klass ||= class_name.constantize
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns the class name for the macro.
|
56
|
+
#
|
57
|
+
# <tt>has_many :clients</tt> returns <tt>'Client'</tt>
|
58
|
+
def class_name
|
59
|
+
@class_name ||= derive_class_name
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns the foreign_key for the macro.
|
63
|
+
def foreign_key
|
64
|
+
@foreign_key ||= self.options[:foreign_key] || "#{self.name.to_s.downcase}_id"
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
def derive_class_name
|
69
|
+
return (options[:class_name] ? options[:class_name].to_s.camelize : name.to_s.classify)
|
70
|
+
end
|
71
|
+
|
72
|
+
def derive_foreign_key
|
73
|
+
return options[:foreign_key] ? options[:foreign_key].to_s : "#{name.to_s.downcase}_id"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module ActiveResource # :nodoc:
|
2
|
+
class Schema # :nodoc:
|
3
|
+
# attributes can be known to be one of these types. They are easy to
|
4
|
+
# cast to/from.
|
5
|
+
KNOWN_ATTRIBUTE_TYPES = %w( string text integer float decimal datetime timestamp time date binary boolean )
|
6
|
+
|
7
|
+
# An array of attribute definitions, representing the attributes that
|
8
|
+
# have been defined.
|
9
|
+
attr_accessor :attrs
|
10
|
+
|
11
|
+
# The internals of an Active Resource Schema are very simple -
|
12
|
+
# unlike an Active Record TableDefinition (on which it is based).
|
13
|
+
# It provides a set of convenience methods for people to define their
|
14
|
+
# schema using the syntax:
|
15
|
+
# schema do
|
16
|
+
# string :foo
|
17
|
+
# integer :bar
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# The schema stores the name and type of each attribute. That is then
|
21
|
+
# read out by the schema method to populate the schema of the actual
|
22
|
+
# resource.
|
23
|
+
def initialize
|
24
|
+
@attrs = {}
|
25
|
+
end
|
26
|
+
|
27
|
+
def attribute(name, type, options = {})
|
28
|
+
raise ArgumentError, "Unknown Attribute type: #{type.inspect} for key: #{name.inspect}" unless type.nil? || Schema::KNOWN_ATTRIBUTE_TYPES.include?(type.to_s)
|
29
|
+
|
30
|
+
the_type = type.to_s
|
31
|
+
# TODO: add defaults
|
32
|
+
#the_attr = [type.to_s]
|
33
|
+
#the_attr << options[:default] if options.has_key? :default
|
34
|
+
@attrs[name.to_s] = the_type
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
# The following are the attribute types supported by Active Resource
|
39
|
+
# migrations.
|
40
|
+
KNOWN_ATTRIBUTE_TYPES.each do |attr_type|
|
41
|
+
# def string(*args)
|
42
|
+
# options = args.extract_options!
|
43
|
+
# attr_names = args
|
44
|
+
#
|
45
|
+
# attr_names.each { |name| attribute(name, 'string', options) }
|
46
|
+
# end
|
47
|
+
class_eval <<-EOV, __FILE__, __LINE__ + 1
|
48
|
+
def #{attr_type.to_s}(*args)
|
49
|
+
options = args.extract_options!
|
50
|
+
attr_names = args
|
51
|
+
|
52
|
+
attr_names.each { |name| attribute(name, '#{attr_type}', options) }
|
53
|
+
end
|
54
|
+
EOV
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module ActiveResource
|
2
|
+
module Singleton
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
attr_writer :singleton_name
|
7
|
+
|
8
|
+
def singleton_name
|
9
|
+
@singleton_name ||= model_name.element
|
10
|
+
end
|
11
|
+
|
12
|
+
# Gets the singleton path for the object. If the +query_options+ parameter is omitted, Rails
|
13
|
+
# will split from the \prefix options.
|
14
|
+
#
|
15
|
+
# ==== Options
|
16
|
+
# * +prefix_options+ - A \hash to add a \prefix to the request for nested URLs (e.g., <tt>:account_id => 19</tt>
|
17
|
+
# would yield a URL like <tt>/accounts/19/purchases.json</tt>).
|
18
|
+
#
|
19
|
+
# * +query_options+ - A \hash to add items to the query string for the request.
|
20
|
+
#
|
21
|
+
# ==== Examples
|
22
|
+
# Weather.singleton_path
|
23
|
+
# # => /weather.json
|
24
|
+
#
|
25
|
+
# class Inventory < ActiveResource::Base
|
26
|
+
# self.site = "https://37s.sunrise.com"
|
27
|
+
# self.prefix = "/products/:product_id/"
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# Inventory.singleton_path(:product_id => 5)
|
31
|
+
# # => /products/5/inventory.json
|
32
|
+
#
|
33
|
+
# Inventory.singleton_path({:product_id => 5}, {:sold => true})
|
34
|
+
# # => /products/5/inventory.json?sold=true
|
35
|
+
#
|
36
|
+
def singleton_path(prefix_options = {}, query_options = nil)
|
37
|
+
check_prefix_options(prefix_options)
|
38
|
+
|
39
|
+
prefix_options, query_options = split_options(prefix_options) if query_options.nil?
|
40
|
+
"#{prefix(prefix_options)}#{singleton_name}#{format_extension}#{query_string(query_options)}"
|
41
|
+
end
|
42
|
+
|
43
|
+
# Core method for finding singleton resources.
|
44
|
+
#
|
45
|
+
# ==== Arguments
|
46
|
+
# Takes a single argument of options
|
47
|
+
#
|
48
|
+
# ==== Options
|
49
|
+
# * <tt>:params</tt> - Sets the query and \prefix (nested URL) parameters.
|
50
|
+
#
|
51
|
+
# ==== Examples
|
52
|
+
# Weather.find
|
53
|
+
# # => GET /weather.json
|
54
|
+
#
|
55
|
+
# Weather.find(:params => {:degrees => 'fahrenheit'})
|
56
|
+
# # => GET /weather.json?degrees=fahrenheit
|
57
|
+
#
|
58
|
+
# == Failure or missing data
|
59
|
+
# A failure to find the requested object raises a ResourceNotFound exception.
|
60
|
+
#
|
61
|
+
# Inventory.find
|
62
|
+
# # => raises ResourceNotFound
|
63
|
+
def find(options={})
|
64
|
+
find_singleton(options)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
# Find singleton resource
|
69
|
+
def find_singleton(options)
|
70
|
+
prefix_options, query_options = split_options(options[:params])
|
71
|
+
|
72
|
+
path = singleton_path(prefix_options, query_options)
|
73
|
+
resp = self.format.decode(self.connection.get(path, self.headers).body)
|
74
|
+
instantiate_record(resp, prefix_options)
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
# Deletes the resource from the remote service.
|
79
|
+
#
|
80
|
+
# ==== Examples
|
81
|
+
# weather = Weather.find
|
82
|
+
# weather.destroy
|
83
|
+
# Weather.find # 404 (Resource Not Found)
|
84
|
+
def destroy
|
85
|
+
connection.delete(singleton_path, self.class.headers)
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
protected
|
90
|
+
|
91
|
+
# Update the resource on the remote service
|
92
|
+
def update
|
93
|
+
connection.put(singleton_path(prefix_options), encode, self.class.headers).tap do |response|
|
94
|
+
load_attributes_from_response(response)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Create (i.e. \save to the remote service) the \new resource.
|
99
|
+
def create
|
100
|
+
connection.post(singleton_path, encode, self.class.headers).tap do |response|
|
101
|
+
self.id = id_from_response(response)
|
102
|
+
load_attributes_from_response(response)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
def singleton_path(options = nil)
|
109
|
+
self.class.singleton_path(options || prefix_options)
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'active_support/core_ext/object/duplicable'
|
2
|
+
|
3
|
+
module ThreadsafeAttributes
|
4
|
+
def self.included(klass)
|
5
|
+
klass.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def threadsafe_attribute(*attrs)
|
10
|
+
main_thread = Thread.main # remember this, because it could change after forking
|
11
|
+
|
12
|
+
attrs.each do |attr|
|
13
|
+
define_method attr do
|
14
|
+
get_threadsafe_attribute(attr, main_thread)
|
15
|
+
end
|
16
|
+
|
17
|
+
define_method "#{attr}=" do |value|
|
18
|
+
set_threadsafe_attribute(attr, value, main_thread)
|
19
|
+
end
|
20
|
+
|
21
|
+
define_method "#{attr}_defined?" do
|
22
|
+
threadsafe_attribute_defined?(attr, main_thread)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def get_threadsafe_attribute(name, main_thread)
|
31
|
+
if threadsafe_attribute_defined_by_thread?(name, Thread.current)
|
32
|
+
get_threadsafe_attribute_by_thread(name, Thread.current)
|
33
|
+
elsif threadsafe_attribute_defined_by_thread?(name, main_thread)
|
34
|
+
value = get_threadsafe_attribute_by_thread(name, main_thread)
|
35
|
+
value = value.dup if value.duplicable?
|
36
|
+
set_threadsafe_attribute_by_thread(name, value, Thread.current)
|
37
|
+
value
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def set_threadsafe_attribute(name, value, main_thread)
|
42
|
+
set_threadsafe_attribute_by_thread(name, value, Thread.current)
|
43
|
+
unless threadsafe_attribute_defined_by_thread?(name, main_thread)
|
44
|
+
set_threadsafe_attribute_by_thread(name, value, main_thread)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def threadsafe_attribute_defined?(name, main_thread)
|
49
|
+
threadsafe_attribute_defined_by_thread?(name, Thread.current) || ((Thread.current != main_thread) && threadsafe_attribute_defined_by_thread?(name, main_thread))
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_threadsafe_attribute_by_thread(name, thread)
|
53
|
+
thread["active.resource.#{name}.#{self.object_id}"]
|
54
|
+
end
|
55
|
+
|
56
|
+
def set_threadsafe_attribute_by_thread(name, value, thread)
|
57
|
+
thread["active.resource.#{name}.#{self.object_id}.defined"] = true
|
58
|
+
thread["active.resource.#{name}.#{self.object_id}"] = value
|
59
|
+
end
|
60
|
+
|
61
|
+
def threadsafe_attribute_defined_by_thread?(name, thread)
|
62
|
+
thread["active.resource.#{name}.#{self.object_id}.defined"]
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
require 'active_support/core_ext/array/wrap'
|
2
|
+
require 'active_support/core_ext/object/blank'
|
3
|
+
|
4
|
+
module ActiveResource
|
5
|
+
class ResourceInvalid < ClientError #:nodoc:
|
6
|
+
end
|
7
|
+
|
8
|
+
# Active Resource validation is reported to and from this object, which is used by Base#save
|
9
|
+
# to determine whether the object in a valid state to be saved. See usage example in Validations.
|
10
|
+
class Errors < ActiveModel::Errors
|
11
|
+
# Grabs errors from an array of messages (like ActiveRecord::Validations).
|
12
|
+
# The second parameter directs the errors cache to be cleared (default)
|
13
|
+
# or not (by passing true).
|
14
|
+
def from_array(messages, save_cache = false)
|
15
|
+
clear unless save_cache
|
16
|
+
humanized_attributes = Hash[@base.known_attributes.map { |attr_name| [attr_name.humanize, attr_name] }]
|
17
|
+
messages.each do |message|
|
18
|
+
attr_message = humanized_attributes.keys.sort_by { |a| -a.length }.detect do |attr_name|
|
19
|
+
if message[0, attr_name.size + 1] == "#{attr_name} "
|
20
|
+
add humanized_attributes[attr_name], message[(attr_name.size + 1)..-1]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
self[:base] << message if attr_message.nil?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Grabs errors from a hash of attribute => array of errors elements
|
28
|
+
# The second parameter directs the errors cache to be cleared (default)
|
29
|
+
# or not (by passing true)
|
30
|
+
#
|
31
|
+
# Unrecognized attribute names will be humanized and added to the record's
|
32
|
+
# base errors.
|
33
|
+
def from_hash(messages, save_cache = false)
|
34
|
+
clear unless save_cache
|
35
|
+
|
36
|
+
messages.each do |(key,errors)|
|
37
|
+
errors.each do |error|
|
38
|
+
if @base.known_attributes.include?(key)
|
39
|
+
add key, error
|
40
|
+
elsif key == 'base'
|
41
|
+
self[:base] << error
|
42
|
+
else
|
43
|
+
# reporting an error on an attribute not in attributes
|
44
|
+
# format and add them to base
|
45
|
+
self[:base] << "#{key.humanize} #{error}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Grabs errors from a json response.
|
52
|
+
def from_json(json, save_cache = false)
|
53
|
+
decoded = ActiveSupport::JSON.decode(json) || {} rescue {}
|
54
|
+
if decoded.kind_of?(Hash) && (decoded.has_key?('errors') || decoded.empty?)
|
55
|
+
errors = decoded['errors'] || {}
|
56
|
+
if errors.kind_of?(Array)
|
57
|
+
# 3.2.1-style with array of strings
|
58
|
+
ActiveSupport::Deprecation.warn('Returning errors as an array of strings is deprecated.')
|
59
|
+
from_array errors, save_cache
|
60
|
+
else
|
61
|
+
# 3.2.2+ style
|
62
|
+
from_hash errors, save_cache
|
63
|
+
end
|
64
|
+
else
|
65
|
+
# <3.2-style respond_with - lacks 'errors' key
|
66
|
+
ActiveSupport::Deprecation.warn('Returning errors as a hash without a root "errors" key is deprecated.')
|
67
|
+
from_hash decoded, save_cache
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Grabs errors from an XML response.
|
72
|
+
def from_xml(xml, save_cache = false)
|
73
|
+
array = Array.wrap(Hash.from_xml(xml)['errors']['error']) rescue []
|
74
|
+
from_array array, save_cache
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Module to support validation and errors with Active Resource objects. The module overrides
|
79
|
+
# Base#save to rescue ActiveResource::ResourceInvalid exceptions and parse the errors returned
|
80
|
+
# in the web service response. The module also adds an +errors+ collection that mimics the interface
|
81
|
+
# of the errors provided by ActiveModel::Errors.
|
82
|
+
#
|
83
|
+
# ==== Example
|
84
|
+
#
|
85
|
+
# Consider a Person resource on the server requiring both a +first_name+ and a +last_name+ with a
|
86
|
+
# <tt>validates_presence_of :first_name, :last_name</tt> declaration in the model:
|
87
|
+
#
|
88
|
+
# person = Person.new(:first_name => "Jim", :last_name => "")
|
89
|
+
# person.save # => false (server returns an HTTP 422 status code and errors)
|
90
|
+
# person.valid? # => false
|
91
|
+
# person.errors.empty? # => false
|
92
|
+
# person.errors.count # => 1
|
93
|
+
# person.errors.full_messages # => ["Last name can't be empty"]
|
94
|
+
# person.errors[:last_name] # => ["can't be empty"]
|
95
|
+
# person.last_name = "Halpert"
|
96
|
+
# person.save # => true (and person is now saved to the remote service)
|
97
|
+
#
|
98
|
+
module Validations
|
99
|
+
extend ActiveSupport::Concern
|
100
|
+
include ActiveModel::Validations
|
101
|
+
|
102
|
+
included do
|
103
|
+
alias_method :save_without_validation, :save
|
104
|
+
alias_method :save, :save_with_validation
|
105
|
+
end
|
106
|
+
|
107
|
+
# Validate a resource and save (POST) it to the remote web service.
|
108
|
+
# If any local validations fail - the save (POST) will not be attempted.
|
109
|
+
def save_with_validation(options={})
|
110
|
+
perform_validation = options[:validate] != false
|
111
|
+
|
112
|
+
# clear the remote validations so they don't interfere with the local
|
113
|
+
# ones. Otherwise we get an endless loop and can never change the
|
114
|
+
# fields so as to make the resource valid.
|
115
|
+
@remote_errors = nil
|
116
|
+
if perform_validation && valid? || !perform_validation
|
117
|
+
save_without_validation
|
118
|
+
true
|
119
|
+
else
|
120
|
+
false
|
121
|
+
end
|
122
|
+
rescue ResourceInvalid => error
|
123
|
+
# cache the remote errors because every call to <tt>valid?</tt> clears
|
124
|
+
# all errors. We must keep a copy to add these back after local
|
125
|
+
# validations.
|
126
|
+
@remote_errors = error
|
127
|
+
load_remote_errors(@remote_errors, true)
|
128
|
+
false
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
# Loads the set of remote errors into the object's Errors based on the
|
133
|
+
# content-type of the error-block received.
|
134
|
+
def load_remote_errors(remote_errors, save_cache = false ) #:nodoc:
|
135
|
+
case self.class.format
|
136
|
+
when ActiveResource::Formats[:xml]
|
137
|
+
errors.from_xml(remote_errors.response.body, save_cache)
|
138
|
+
when ActiveResource::Formats[:json]
|
139
|
+
errors.from_json(remote_errors.response.body, save_cache)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# Checks for errors on an object (i.e., is resource.errors empty?).
|
144
|
+
#
|
145
|
+
# Runs all the specified local validations and returns true if no errors
|
146
|
+
# were added, otherwise false.
|
147
|
+
# Runs local validations (eg those on your Active Resource model), and
|
148
|
+
# also any errors returned from the remote system the last time we
|
149
|
+
# saved.
|
150
|
+
# Remote errors can only be cleared by trying to re-save the resource.
|
151
|
+
#
|
152
|
+
# ==== Examples
|
153
|
+
# my_person = Person.create(params[:person])
|
154
|
+
# my_person.valid?
|
155
|
+
# # => true
|
156
|
+
#
|
157
|
+
# my_person.errors.add('login', 'can not be empty') if my_person.login == ''
|
158
|
+
# my_person.valid?
|
159
|
+
# # => false
|
160
|
+
#
|
161
|
+
def valid?
|
162
|
+
run_callbacks :validate do
|
163
|
+
super
|
164
|
+
load_remote_errors(@remote_errors, true) if defined?(@remote_errors) && @remote_errors.present?
|
165
|
+
errors.empty?
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# Returns the Errors object that holds all information about attribute error messages.
|
170
|
+
def errors
|
171
|
+
@errors ||= Errors.new(self)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|