restly 0.0.1.beta.3 → 0.0.1.beta.4
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/lib/restly/base/instance/actions.rb +2 -2
- data/lib/restly/base/instance/error_handling.rb +16 -6
- data/lib/restly/base/instance/persistence.rb +2 -2
- data/lib/restly/base/instance/write_callbacks.rb +43 -27
- data/lib/restly/base/resource/finders.rb +1 -0
- data/lib/restly/base/resource/specification/fields.rb +3 -3
- data/lib/restly/connection.rb +9 -6
- data/lib/restly/embedded_associations/class_methods.rb +9 -2
- data/lib/restly/nested_attributes.rb +49 -13
- data/lib/restly/version.rb +1 -1
- metadata +2 -2
@@ -25,13 +25,13 @@ module Restly::Base::Instance::Actions
|
|
25
25
|
|
26
26
|
def update
|
27
27
|
run_callbacks :update do
|
28
|
-
set_response(connection.put path_with_format, body:
|
28
|
+
set_response(connection.put path_with_format, body: formatted_for_request, params: params)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
32
|
def create
|
33
33
|
run_callbacks :create do
|
34
|
-
set_response(connection.post path_with_format, body:
|
34
|
+
set_response(connection.post path_with_format, body: formatted_for_request, params: params)
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
@@ -1,6 +1,14 @@
|
|
1
1
|
module Restly::Base::Instance::ErrorHandling
|
2
2
|
extend ActiveSupport::Concern
|
3
3
|
|
4
|
+
def append_error(field, error)
|
5
|
+
self.errors.add field.to_sym, error
|
6
|
+
if /(?<association>\w+)\.(?<attr>.+)/ =~ field && respond_to_association?(association)
|
7
|
+
instance_eval(&association.to_sym).append_error(attr, error)
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
|
4
12
|
private
|
5
13
|
|
6
14
|
def response_has_errors?(response=self.response)
|
@@ -20,21 +28,23 @@ module Restly::Base::Instance::ErrorHandling
|
|
20
28
|
case error
|
21
29
|
|
22
30
|
when Array
|
23
|
-
error.each { |e|
|
31
|
+
error.each { |e| append_error name, e }
|
24
32
|
|
25
33
|
when String
|
26
|
-
|
34
|
+
append_error name, error
|
27
35
|
|
28
36
|
end
|
37
|
+
|
29
38
|
end
|
30
39
|
|
31
40
|
when Array
|
32
|
-
response_errors.each
|
33
|
-
self.errors.add(:base, error)
|
34
|
-
end
|
41
|
+
response_errors.each { |error| append_error :base, error }
|
35
42
|
|
36
43
|
when String
|
37
|
-
|
44
|
+
append_error :base, response_errors
|
45
|
+
|
46
|
+
when NilClass
|
47
|
+
append_error :base, connection.status_string(response.status)
|
38
48
|
|
39
49
|
end
|
40
50
|
|
@@ -4,7 +4,7 @@ module Restly::Base::Instance::Persistence
|
|
4
4
|
return false unless id
|
5
5
|
|
6
6
|
begin
|
7
|
-
@response
|
7
|
+
@response = connection.get(path, force: true) unless @response.status.to_i < 400
|
8
8
|
|
9
9
|
rescue OAuth2::Error => e
|
10
10
|
@response = e.response
|
@@ -12,7 +12,7 @@ module Restly::Base::Instance::Persistence
|
|
12
12
|
end
|
13
13
|
|
14
14
|
status = @response.status.to_i
|
15
|
-
status <
|
15
|
+
status < 400 && status >= 200
|
16
16
|
|
17
17
|
end
|
18
18
|
|
@@ -2,47 +2,63 @@ module Restly::Base::Instance::WriteCallbacks
|
|
2
2
|
extend ActiveSupport::Concern
|
3
3
|
|
4
4
|
included do
|
5
|
-
|
6
|
-
end
|
5
|
+
extend ClassMethods
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
when :json
|
13
|
-
savable_resource.to_json
|
14
|
-
when :xml
|
15
|
-
savable_resource.to_xml
|
16
|
-
else
|
17
|
-
savable_resource.to_param
|
18
|
-
end
|
19
|
-
end
|
7
|
+
class_attribute :request_builders
|
8
|
+
self.request_builders = []
|
9
|
+
|
10
|
+
build_request :attributes
|
20
11
|
|
21
|
-
def savable_resource
|
22
|
-
{resource_name => attributes_with_present_values(writable_attributes)}
|
23
12
|
end
|
24
13
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
14
|
+
def formatted_for_request
|
15
|
+
|
16
|
+
case format.to_sym
|
17
|
+
when :json
|
18
|
+
built_for_request.to_json
|
19
|
+
|
20
|
+
when :xml
|
21
|
+
built_for_request.to_xml
|
22
|
+
|
23
|
+
else
|
24
|
+
built_for_request.to_param
|
25
|
+
|
33
26
|
end
|
27
|
+
|
34
28
|
end
|
35
29
|
|
36
|
-
def
|
30
|
+
def built_for_request(resource_key=resource_name)
|
31
|
+
|
32
|
+
attributes = request_builders.reduce(HashWithIndifferentAccess.new) do |attributes, builder|
|
33
|
+
attributes.merge! builder.is_a?(Symbol) ? send(builder) : instance_eval(&builder)
|
34
|
+
end
|
35
|
+
|
37
36
|
maa = mass_assignment_authorizer(:default)
|
38
37
|
|
39
38
|
if maa.is_a? ActiveModel::MassAssignmentSecurity::BlackList
|
40
|
-
attributes.
|
39
|
+
attributes.except! *maa.map(&:to_sym)
|
41
40
|
|
42
41
|
elsif maa.is_a? ActiveModel::MassAssignmentSecurity::WhiteList
|
43
|
-
attributes.
|
42
|
+
attributes.slice! *maa.map(&:to_sym)
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
if resource_key
|
47
|
+
{ resource_key.to_sym => attributes.select { |k,v| v.present? } }
|
48
|
+
else
|
49
|
+
attributes.select { |k,v| v.present? }
|
50
|
+
end
|
44
51
|
|
52
|
+
end
|
53
|
+
|
54
|
+
module ClassMethods
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def build_request(symbol=nil, &block)
|
59
|
+
self.request_builders << symbol || block
|
45
60
|
end
|
61
|
+
|
46
62
|
end
|
47
63
|
|
48
64
|
|
@@ -24,6 +24,7 @@ module Restly::Base::Resource::Finders
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def instance_from_response(response)
|
27
|
+
raise Restly::Error::RecordNotFound, "Could not find a #{name} at the specified path." unless response.status < 400
|
27
28
|
new(nil, response: response, connection: connection)
|
28
29
|
end
|
29
30
|
|
@@ -10,12 +10,12 @@ class Restly::Base::Resource::Specification::Fields < Restly::Proxies::Base
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def - field
|
13
|
-
@removed
|
13
|
+
@removed += field
|
14
14
|
replace(__getobj__.send __method__, field)
|
15
15
|
end
|
16
16
|
|
17
17
|
def + field
|
18
|
-
@added
|
18
|
+
@added += field
|
19
19
|
replace(__getobj__.send __method__, field)
|
20
20
|
end
|
21
21
|
|
@@ -38,7 +38,7 @@ class Restly::Base::Resource::Specification::Fields < Restly::Proxies::Base
|
|
38
38
|
|
39
39
|
def reload_specification!
|
40
40
|
from_spec = spec[:attributes] || []
|
41
|
-
fields = (from_spec - @removed.
|
41
|
+
fields = (from_spec.map(&:to_sym) - @removed.map(&:to_sym)) + @added.map(&:to_sym)
|
42
42
|
__setobj__ Restly::Base::Fields::FieldSet.new(spec.model, fields)
|
43
43
|
end
|
44
44
|
|
data/lib/restly/connection.rb
CHANGED
@@ -61,10 +61,15 @@ class Restly::Connection < OAuth2::AccessToken
|
|
61
61
|
}
|
62
62
|
end
|
63
63
|
|
64
|
+
def status_string(int)
|
65
|
+
Rack::Utils::HTTP_STATUS_CODES[int.to_i]
|
66
|
+
end
|
67
|
+
|
64
68
|
alias_method :forced_request, :request
|
65
69
|
|
66
70
|
def request(verb, path, opts={}, &block)
|
67
|
-
|
71
|
+
|
72
|
+
path = [base_path.gsub(/\/?$/, ''), path.gsub(/^\/?/, '')].join('/') unless /#{base_path}/.match path
|
68
73
|
|
69
74
|
if cache && !opts[:force]
|
70
75
|
request_log("Restly::CacheRequest", path, verb) do
|
@@ -77,6 +82,8 @@ class Restly::Connection < OAuth2::AccessToken
|
|
77
82
|
end
|
78
83
|
end
|
79
84
|
|
85
|
+
private
|
86
|
+
|
80
87
|
def id_from_path(path)
|
81
88
|
capture = path.match /(?<id>[0-9])\.\w*$/
|
82
89
|
capture[:id] if capture
|
@@ -123,7 +130,7 @@ class Restly::Connection < OAuth2::AccessToken
|
|
123
130
|
|
124
131
|
if response.status >= 500
|
125
132
|
site = URI.parse(client.site)
|
126
|
-
formatted_path = ["#{site.scheme}://#{site.host}", "
|
133
|
+
formatted_path = ["#{site.scheme}://#{site.host}", ":#{site.port}", path].join
|
127
134
|
raise Restly::Error::ConnectionError, "#{response.status}: #{status_string(response.status)}\nurl: #{formatted_path}"
|
128
135
|
end
|
129
136
|
|
@@ -142,8 +149,4 @@ class Restly::Connection < OAuth2::AccessToken
|
|
142
149
|
ActiveSupport::Notifications.instrument("cache.restly", key: key, name: name, color: color, &block)
|
143
150
|
end
|
144
151
|
|
145
|
-
def status_string(int)
|
146
|
-
Rack::Utils::HTTP_STATUS_CODES[int.to_i]
|
147
|
-
end
|
148
|
-
|
149
152
|
end
|
@@ -4,7 +4,7 @@ module Restly::EmbeddedAssociations::ClassMethods
|
|
4
4
|
|
5
5
|
# Embeds One
|
6
6
|
def embeds_resource(name, options = {})
|
7
|
-
exclude_field(name)
|
7
|
+
exclude_field(name)
|
8
8
|
self.resource_associations[name] = association = Restly::EmbeddedAssociations::EmbedsOne.new(self, name, options)
|
9
9
|
|
10
10
|
define_method name do |options={}|
|
@@ -20,7 +20,7 @@ module Restly::EmbeddedAssociations::ClassMethods
|
|
20
20
|
|
21
21
|
# Embeds Many
|
22
22
|
def embeds_resources(name, options = {})
|
23
|
-
exclude_field(name)
|
23
|
+
exclude_field(name)
|
24
24
|
self.resource_associations[name] = association = Restly::EmbeddedAssociations::EmbedsMany.new(self, name, options)
|
25
25
|
|
26
26
|
define_method name do |options={}|
|
@@ -43,6 +43,13 @@ module Restly::EmbeddedAssociations::ClassMethods
|
|
43
43
|
define_method "#{name}=" do |value|
|
44
44
|
set_association name, value
|
45
45
|
end
|
46
|
+
|
47
|
+
[:save, :delete, :destroy].each do |method|
|
48
|
+
define_method method do
|
49
|
+
raise NotImplemented, "Embedded actions have not been implemented."
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
46
53
|
end
|
47
54
|
|
48
55
|
end
|
@@ -6,23 +6,28 @@ module Restly::NestedAttributes
|
|
6
6
|
|
7
7
|
included do
|
8
8
|
class_attribute :resource_nested_attributes_options, :instance_writer => false
|
9
|
-
self.resource_nested_attributes_options =
|
9
|
+
self.resource_nested_attributes_options = HashWithIndifferentAccess.new
|
10
10
|
|
11
11
|
inherited do
|
12
12
|
self.resource_nested_attributes_options = resource_nested_attributes_options.dup
|
13
13
|
end
|
14
14
|
|
15
|
+
if ancestors.include?(Restly::Base)
|
16
|
+
include Restly::Base::Instance::WriteCallbacks
|
17
|
+
build_request :nested_attributes_for_request
|
18
|
+
else
|
19
|
+
before_save :save_nested_attributes_associations
|
20
|
+
end
|
21
|
+
|
15
22
|
end
|
16
23
|
|
17
24
|
private
|
18
25
|
|
19
26
|
# One To One Association
|
20
|
-
def assign_nested_attributes_for_one_to_one_resource_association( association_name, attributes )
|
27
|
+
def assign_nested_attributes_for_one_to_one_resource_association( association_name, attributes={} )
|
21
28
|
|
22
|
-
|
23
|
-
associated_instance =
|
24
|
-
self.class.reflect_on_resource_association(association_name).build(self)
|
25
|
-
associated_instance.attributes = association_attributes
|
29
|
+
associated_instance = send(association_name) || self.class.reflect_on_resource_association(association_name).build(self)
|
30
|
+
associated_instance.attributes = attributes
|
26
31
|
|
27
32
|
end
|
28
33
|
|
@@ -57,15 +62,40 @@ module Restly::NestedAttributes
|
|
57
62
|
|
58
63
|
end
|
59
64
|
|
60
|
-
def
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
+
def nested_attributes_for_request
|
66
|
+
resource_nested_attributes_options.reduce(HashWithIndifferentAccess.new) do |hash, (association_name, options)|
|
67
|
+
association = self.class.reflect_on_resource_association association_name.to_sym
|
68
|
+
next unless association.options[:autosave]
|
69
|
+
|
70
|
+
associated_object = instance_eval(&association_name.to_sym)
|
71
|
+
built_for_request = if associated_object.is_a? Array
|
72
|
+
associated_object.map { |instance| instance.built_for_request(nil) if instance.changed? }.compact
|
73
|
+
else
|
74
|
+
associated_object.built_for_request(nil) if associated_object.changed?
|
75
|
+
end
|
76
|
+
|
77
|
+
key = [ options[:write_prefix], association_name, options[:write_suffix] ].compact.join('_')
|
78
|
+
hash[key] = built_for_request if built_for_request.present?
|
65
79
|
hash
|
66
80
|
end
|
67
81
|
end
|
68
82
|
|
83
|
+
def save_nested_attributes_associations
|
84
|
+
resource_nested_attributes_options.each do |association_name, options|
|
85
|
+
association = self.class.reflect_on_resource_association association_name.to_sym
|
86
|
+
next unless association.options[:autosave]
|
87
|
+
|
88
|
+
associated_object = instance_eval(&association_name.to_sym)
|
89
|
+
if associated_object.is_a? Array
|
90
|
+
associated_object.each do |instance|
|
91
|
+
instance.save && instance.changed?
|
92
|
+
end
|
93
|
+
else
|
94
|
+
associated_object.save if associated_object.changed?
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
69
99
|
def nested_attribute_missing(m, *args)
|
70
100
|
if !!(matched = ATTR_MATCHER.match m) && (options = resource_nested_attributes_options[(attr = matched[:attr])])
|
71
101
|
send( "assign_nested_attributes_for_#{options[:association_type]}_resource_association", attr, *args )
|
@@ -80,6 +110,14 @@ module Restly::NestedAttributes
|
|
80
110
|
super
|
81
111
|
end
|
82
112
|
|
113
|
+
def respond_to_nested_attributes?(m)
|
114
|
+
(matched = ATTR_MATCHER.match m) && resource_nested_attributes_options.has_key?(matched[:attr].to_sym)
|
115
|
+
end
|
116
|
+
|
117
|
+
def respond_to?(m, include_private = false)
|
118
|
+
respond_to_nested_attributes?(m) || super
|
119
|
+
end
|
120
|
+
|
83
121
|
module ClassMethods
|
84
122
|
REJECT_ALL_BLANK_PROC = proc { |attributes| attributes.all? { |key, value| key == '_destroy' || value.blank? } }
|
85
123
|
|
@@ -89,8 +127,6 @@ module Restly::NestedAttributes
|
|
89
127
|
options.assert_valid_keys(:allow_destroy, :reject_if, :limit, :update_only, :write_prefix, :write_suffix)
|
90
128
|
options[:reject_if] = REJECT_ALL_BLANK_PROC if options[:reject_if] == :all_blank
|
91
129
|
|
92
|
-
before_save :set_nested_attributes_for_save
|
93
|
-
|
94
130
|
attr_names.each do |association_name|
|
95
131
|
|
96
132
|
if ( reflection = reflect_on_resource_association(association_name) )
|
data/lib/restly/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: restly
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.1.beta.
|
4
|
+
version: 0.0.1.beta.4
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-11-
|
12
|
+
date: 2012-11-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: oauth2
|