toast 0.8.13 → 0.8.14
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/README.md +11 -6
- data/app/controller/toast_controller.rb +36 -1
- data/lib/toast/association.rb +26 -6
- data/lib/toast/collection.rb +25 -17
- data/lib/toast/config_dsl.rb +12 -1
- data/lib/toast/resource.rb +36 -0
- data/lib/toast/version.rb +1 -1
- metadata +109 -66
- checksums.yaml +0 -7
data/README.md
CHANGED
@@ -23,16 +23,21 @@ Toast works with
|
|
23
23
|
|
24
24
|
See the [User Manual](https://github.com/robokopp/toast/wiki/User-Manual) for a detailed description.
|
25
25
|
|
26
|
+
Status
|
27
|
+
=====
|
28
|
+
|
29
|
+
Toast is ready for production and is being used in productive
|
30
|
+
applications since 2012. However, misconfigurations can have undesired
|
31
|
+
effects.
|
32
|
+
|
26
33
|
WARNING
|
27
34
|
=======
|
28
35
|
|
29
|
-
|
30
|
-
|
31
|
-
|
36
|
+
A soon the gem is loaded a controller with ready routing is enabled
|
37
|
+
serving the annotated model's data records at least for reading for
|
38
|
+
everybody.
|
32
39
|
|
33
|
-
|
34
|
-
which will be finished within 2012. Until then API/DSL changes must
|
35
|
-
be expected with each minor update.
|
40
|
+
You need to implement authorization yourself.
|
36
41
|
|
37
42
|
Example
|
38
43
|
=======
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'rack-link_headers'
|
2
|
+
|
1
3
|
class ToastController < ApplicationController
|
2
4
|
|
3
5
|
def catch_all
|
@@ -11,7 +13,37 @@ class ToastController < ApplicationController
|
|
11
13
|
request.headers["LINK"] =~ /(#{request.protocol + request.host + request.script_name})(.*)/
|
12
14
|
end
|
13
15
|
|
14
|
-
|
16
|
+
toast_response = @resource.apply(request.method, request.body.read, request.content_type, $2)
|
17
|
+
|
18
|
+
# pagination
|
19
|
+
if pi = toast_response[:pagination_info]
|
20
|
+
# URL w/o parameters
|
21
|
+
|
22
|
+
url = request.url.split('?').first
|
23
|
+
qpar = request.query_parameters.clone
|
24
|
+
|
25
|
+
# change/add page parameter
|
26
|
+
link_header = []
|
27
|
+
|
28
|
+
if pi[:prev]
|
29
|
+
qpar[:page] = pi[:prev]
|
30
|
+
response.link "#{url}?#{qpar.to_query}", :rel => :prev
|
31
|
+
end
|
32
|
+
|
33
|
+
if pi[:next]
|
34
|
+
qpar[:page] = pi[:next]
|
35
|
+
response.link "#{url}?#{qpar.to_query}", :rel => :next
|
36
|
+
end
|
37
|
+
|
38
|
+
qpar[:page] = pi[:last]
|
39
|
+
response.link "#{url}?#{qpar.to_query}", :rel => :last
|
40
|
+
|
41
|
+
qpar[:page] = 1
|
42
|
+
response.link "#{url}?#{qpar.to_query}", :rel => :first
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
render toast_response
|
15
47
|
|
16
48
|
rescue Toast::ResourceNotFound => e
|
17
49
|
return head(:not_found)
|
@@ -22,6 +54,9 @@ class ToastController < ApplicationController
|
|
22
54
|
rescue Toast::PayloadFormatError => e
|
23
55
|
return head(:bad_request)
|
24
56
|
|
57
|
+
rescue Toast::BadRequest => e
|
58
|
+
return head(:bad_request)
|
59
|
+
|
25
60
|
rescue Toast::MethodNotAllowed => e
|
26
61
|
return head(:method_not_allowed)
|
27
62
|
|
data/lib/toast/association.rb
CHANGED
@@ -29,18 +29,24 @@ module Toast
|
|
29
29
|
|
30
30
|
reflection = @model.reflect_on_association(@assoc.to_sym)
|
31
31
|
|
32
|
-
|
32
|
+
if reflection.collection?
|
33
|
+
|
34
|
+
|
33
35
|
if(@config.pass_params_to.include?(@assoc) and
|
34
36
|
reflection.options[:extend] and
|
35
37
|
reflection.options[:extend].detect{|e| e.method_defined? :find_by_params} )
|
36
|
-
|
38
|
+
|
39
|
+
result, pagination_info = paginate_query( @config, @assoc,
|
40
|
+
@record.send(@assoc).find_by_params(@params), @params)
|
37
41
|
else
|
38
|
-
|
42
|
+
|
43
|
+
result, pagination_info = paginate_query( @config, @assoc,
|
44
|
+
@record.send(@assoc), @params)
|
45
|
+
|
39
46
|
end
|
40
47
|
|
41
|
-
|
48
|
+
raise ResourceNotFound if result.nil?
|
42
49
|
|
43
|
-
if result.is_a? ActiveRecord::Relation or result.is_a? Array
|
44
50
|
{
|
45
51
|
:json => result.map{|r|
|
46
52
|
r.represent( @associate_config_out.in_collection.exposed_attributes,
|
@@ -49,9 +55,23 @@ module Toast
|
|
49
55
|
@associate_config_out.media_type )
|
50
56
|
},
|
51
57
|
:status => :ok,
|
52
|
-
:content_type => @associate_config_out.in_collection.media_type
|
58
|
+
:content_type => @associate_config_out.in_collection.media_type,
|
59
|
+
:pagination_info => pagination_info
|
53
60
|
}
|
61
|
+
|
54
62
|
else
|
63
|
+
|
64
|
+
result =
|
65
|
+
if(@config.pass_params_to.include?(@assoc) and
|
66
|
+
reflection.options[:extend] and
|
67
|
+
reflectin.options[:extend].detect{|e| e.method_defined? :find_by_params} )
|
68
|
+
@record.send(@assoc).find_by_params(@params)
|
69
|
+
else
|
70
|
+
@record.send(@assoc)
|
71
|
+
end
|
72
|
+
|
73
|
+
raise ResourceNotFound if result.nil?
|
74
|
+
|
55
75
|
{
|
56
76
|
:json => result.represent( @associate_config_out.exposed_attributes,
|
57
77
|
@associate_config_out.exposed_associations,
|
data/lib/toast/collection.rb
CHANGED
@@ -32,27 +32,33 @@ module Toast
|
|
32
32
|
# will be successful, but if it's not checked the error
|
33
33
|
# message is not helpful to find the error.
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
35
|
+
if @config_out.pass_params_to.include?(@collection)
|
36
|
+
if @model.method(@collection).arity**2 != 1
|
37
|
+
raise "Toast Error: Class method '#{@collection}' of model '#{@model}' must accept one parameter, as configured by 'acts_as_resource > pass_params_to'."
|
38
|
+
end
|
39
|
+
|
40
|
+
# fetch results
|
41
|
+
#binding.pry if $halt
|
42
|
+
records, pagination_info = paginate_query( @config_out, @collection,
|
43
|
+
@model.send(@collection, @params),
|
44
|
+
@params )
|
45
|
+
else
|
46
|
+
|
47
|
+
if @model.method(@collection).arity > 0
|
48
|
+
raise "Toast Error: Class method '#{@collection}' of model '#{@model}' must not accept any parameter, as configured by 'acts_as_resource'"
|
49
|
+
end
|
50
|
+
|
51
|
+
records, pagination_info = paginate_query( @config_out, @collection,
|
52
|
+
@model.send(@collection=='all'? 'scoped': @collection), # #scoped ?: #all would trigger query too early
|
53
|
+
@params )
|
54
|
+
end
|
50
55
|
|
51
56
|
case @format
|
52
57
|
when "html"
|
53
58
|
{
|
54
59
|
:template => "resources/#{@model.to_s.pluralize.underscore}",
|
55
|
-
:locals => { @model.to_s.pluralize.underscore.to_sym => records
|
60
|
+
:locals => { @model.to_s.pluralize.underscore.to_sym => records,
|
61
|
+
:pagination_info => pagination_info }
|
56
62
|
}
|
57
63
|
when "json"
|
58
64
|
{
|
@@ -63,7 +69,8 @@ module Toast
|
|
63
69
|
@config_out.media_type)
|
64
70
|
},
|
65
71
|
:status => :ok,
|
66
|
-
:content_type => @config_out.in_collection.media_type
|
72
|
+
:content_type => @config_out.in_collection.media_type,
|
73
|
+
:pagination_info => pagination_info
|
67
74
|
}
|
68
75
|
else
|
69
76
|
raise ResourceNotFound
|
@@ -127,5 +134,6 @@ module Toast
|
|
127
134
|
def unlink l
|
128
135
|
raise MethodNotAllowed
|
129
136
|
end
|
137
|
+
|
130
138
|
end
|
131
139
|
end
|
data/lib/toast/config_dsl.rb
CHANGED
@@ -18,7 +18,7 @@ module Toast
|
|
18
18
|
@in_collection = ConfigDSL::InCollection.new model, self
|
19
19
|
@media_type = "application/json"
|
20
20
|
@apidoc = {}
|
21
|
-
|
21
|
+
@paginations = {}
|
22
22
|
@model.attr_accessible []
|
23
23
|
end
|
24
24
|
|
@@ -112,12 +112,23 @@ module Toast
|
|
112
112
|
@apidoc = arg
|
113
113
|
end
|
114
114
|
|
115
|
+
def paginate collection_name, options={}
|
116
|
+
options.reverse_merge! :page_size => 30
|
117
|
+
|
118
|
+
@paginations[collection_name.to_s] = {:page_size => options[:page_size]}
|
119
|
+
end
|
120
|
+
|
115
121
|
# non DSL methods
|
116
122
|
dsl_methods false
|
117
123
|
|
118
124
|
def field_comments
|
119
125
|
@field_comments
|
120
126
|
end
|
127
|
+
|
128
|
+
def paginations
|
129
|
+
@paginations
|
130
|
+
end
|
131
|
+
|
121
132
|
end
|
122
133
|
|
123
134
|
class InCollection
|
data/lib/toast/resource.rb
CHANGED
@@ -8,6 +8,7 @@ module Toast
|
|
8
8
|
class UnsupportedMediaType < Exception; end
|
9
9
|
class RequestedVersionNotDefined < Exception; end
|
10
10
|
class ResourceNotAcceptable < Exception; end
|
11
|
+
class BadRequest < Exception; end
|
11
12
|
|
12
13
|
# Represents a resource. There are following resource types as sub classes:
|
13
14
|
# Record, Collection, Association, Single
|
@@ -135,5 +136,40 @@ module Toast
|
|
135
136
|
|
136
137
|
out
|
137
138
|
end
|
139
|
+
|
140
|
+
|
141
|
+
def paginate_query config, relation_name, relation, params
|
142
|
+
|
143
|
+
if pagination = config.paginations[relation_name] and params[:page] =~ /\d+/
|
144
|
+
|
145
|
+
raise Toast::BadRequest.new("Page 0 not defined. Paging starts with 1") if params[:page].to_i == 0
|
146
|
+
|
147
|
+
ps = pagination[:page_size].to_i
|
148
|
+
total = relation.count
|
149
|
+
|
150
|
+
page = params[:page].to_i
|
151
|
+
total_pages = (total/ps) + (total%ps == 0 ? 0 : 1)
|
152
|
+
|
153
|
+
pagination_info = {}
|
154
|
+
|
155
|
+
if total_pages > 0
|
156
|
+
|
157
|
+
if page > total_pages
|
158
|
+
pagination_info[:prev] = total_pages
|
159
|
+
else
|
160
|
+
pagination_info[:prev] = page - 1 unless page == 1
|
161
|
+
pagination_info[:next] = page + 1 if page < total_pages
|
162
|
+
end
|
163
|
+
|
164
|
+
pagination_info[:last] = total_pages
|
165
|
+
else
|
166
|
+
pagination_info[:last] = 1
|
167
|
+
end
|
168
|
+
|
169
|
+
[relation.limit(ps).offset((page-1) * ps), pagination_info]
|
170
|
+
else
|
171
|
+
[relation, nil]
|
172
|
+
end
|
173
|
+
end
|
138
174
|
end
|
139
175
|
end
|
data/lib/toast/version.rb
CHANGED
metadata
CHANGED
@@ -1,81 +1,112 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: toast
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 35
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 8
|
9
|
+
- 14
|
10
|
+
version: 0.8.14
|
5
11
|
platform: ruby
|
6
|
-
authors:
|
7
|
-
- robokopp (Robert
|
12
|
+
authors:
|
13
|
+
- "robokopp (Robert Anni\xC3\xA9s)"
|
8
14
|
autorequire:
|
9
15
|
bindir: bin
|
10
16
|
cert_chain: []
|
11
|
-
|
12
|
-
|
13
|
-
|
17
|
+
|
18
|
+
date: 2014-04-14 00:00:00 +02:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
14
22
|
name: rails
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - '>='
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 3.1.0
|
20
|
-
type: :runtime
|
21
23
|
prerelease: false
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 3
|
32
|
+
- 1
|
33
|
+
- 0
|
26
34
|
version: 3.1.0
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: blockenspiel
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ~>
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 0.4.2
|
34
35
|
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: blockenspiel
|
35
39
|
prerelease: false
|
36
|
-
|
37
|
-
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
38
43
|
- - ~>
|
39
|
-
- !ruby/object:Gem::Version
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 11
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
- 4
|
49
|
+
- 2
|
40
50
|
version: 0.4.2
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: rack-accept-media-types
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ~>
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0.9'
|
48
51
|
type: :runtime
|
52
|
+
version_requirements: *id002
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: rack-accept-media-types
|
49
55
|
prerelease: false
|
50
|
-
|
51
|
-
|
56
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
52
59
|
- - ~>
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
|
55
|
-
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 25
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
- 9
|
65
|
+
version: "0.9"
|
66
|
+
type: :runtime
|
67
|
+
version_requirements: *id003
|
68
|
+
- !ruby/object:Gem::Dependency
|
56
69
|
name: ffaker
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
70
|
+
prerelease: false
|
71
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
hash: 3
|
77
|
+
segments:
|
78
|
+
- 0
|
79
|
+
version: "0"
|
62
80
|
type: :runtime
|
81
|
+
version_requirements: *id004
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: rack-link_headers
|
63
84
|
prerelease: false
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
85
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ~>
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
hash: 3
|
91
|
+
segments:
|
92
|
+
- 2
|
93
|
+
- 2
|
94
|
+
- 2
|
95
|
+
version: 2.2.2
|
96
|
+
type: :runtime
|
97
|
+
version_requirements: *id005
|
69
98
|
description: |-
|
70
99
|
Toast is an extension to Ruby on Rails that lets you expose any
|
71
100
|
ActiveRecord model as a resource according to the REST paradigm via a generic controller. The default
|
72
101
|
representation format is JSON or can be anything
|
73
102
|
email: robokopp@fernwerk.net
|
74
103
|
executables: []
|
104
|
+
|
75
105
|
extensions: []
|
76
|
-
|
106
|
+
|
107
|
+
extra_rdoc_files:
|
77
108
|
- README.md
|
78
|
-
files:
|
109
|
+
files:
|
79
110
|
- app/controller/toast_controller.rb
|
80
111
|
- config/routes.rb
|
81
112
|
- lib/toast.rb
|
@@ -89,27 +120,39 @@ files:
|
|
89
120
|
- lib/toast/resource.rb
|
90
121
|
- lib/toast/single.rb
|
91
122
|
- README.md
|
123
|
+
has_rdoc: true
|
92
124
|
homepage: https://github.com/robokopp/toast
|
93
125
|
licenses: []
|
94
|
-
|
126
|
+
|
95
127
|
post_install_message:
|
96
128
|
rdoc_options: []
|
97
|
-
|
129
|
+
|
130
|
+
require_paths:
|
98
131
|
- lib
|
99
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
132
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
133
|
+
none: false
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
hash: 3
|
138
|
+
segments:
|
139
|
+
- 0
|
140
|
+
version: "0"
|
141
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
142
|
+
none: false
|
143
|
+
requirements:
|
144
|
+
- - ">="
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
hash: 3
|
147
|
+
segments:
|
148
|
+
- 0
|
149
|
+
version: "0"
|
109
150
|
requirements: []
|
151
|
+
|
110
152
|
rubyforge_project:
|
111
|
-
rubygems_version:
|
153
|
+
rubygems_version: 1.6.2
|
112
154
|
signing_key:
|
113
|
-
specification_version:
|
155
|
+
specification_version: 3
|
114
156
|
summary: Toast adds a RESTful interface to ActiveRecord models in Ruby on Rails.
|
115
157
|
test_files: []
|
158
|
+
|
checksums.yaml
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
---
|
2
|
-
SHA1:
|
3
|
-
metadata.gz: b312ad41453a5e1c9d8c38fb0ebfc38d0d1c26fe
|
4
|
-
data.tar.gz: c09def11305a4ec61d570f98ef71de7982da41af
|
5
|
-
SHA512:
|
6
|
-
metadata.gz: 6aad28550213a443d1d8b3d0a8b4f4dbf282f83a1295b90c40f7e3cc1155900aaab227276455f24b5343f6bf6b670cc56d2dabe13bcb3799652a4d799692694d
|
7
|
-
data.tar.gz: 42421ba7a9854ce1b8ce0aceaf3c5716fe069ab3e396c90167a895a8a7b84cce0ddcaf4d6b68d38dfbbb86ee61acda3ac9b4f455d8ce8984108f8b93f8eaa819
|