restly 0.0.1.beta.3 → 0.0.1.beta.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|