rack-backend-api 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +47 -0
- data/lib/backend_api.rb +4 -4
- data/lib/sequel_rack_backend_api_adapter.rb +1 -0
- data/rack-backend-api.gemspec +1 -1
- data/test/spec_backend_api.rb +39 -2
- metadata +4 -4
data/README.md
CHANGED
@@ -164,6 +164,52 @@ nice interface using Ajax and getting the best of what the API has to offer.
|
|
164
164
|
The forms are really meant to be requested via an XHR,
|
165
165
|
so that you have access to style and javascript widgets like a date-picker for example.
|
166
166
|
|
167
|
+
Nevertheless you might want to have a better unobtrusiveness for your javascript, meaning
|
168
|
+
you want to be able to wrap the forms yourself with your nice layout.
|
169
|
+
That is also valuable if you want to have no javascript at all.
|
170
|
+
|
171
|
+
This is exactly what the option `_no_wrap` is for. Basically if you want that,
|
172
|
+
it is better to have your Backend middleware before the API in the Rack stack:
|
173
|
+
|
174
|
+
map '/' do
|
175
|
+
run Frontend
|
176
|
+
end
|
177
|
+
|
178
|
+
map '/admin' do
|
179
|
+
use Rack::Auth::Basic, "your-realm" do |username, password|
|
180
|
+
[username, password] == ['username', 'password']
|
181
|
+
end
|
182
|
+
use Backend
|
183
|
+
run BackendAPI
|
184
|
+
end
|
185
|
+
|
186
|
+
Then what you do is that you make your Backend middleware aware that if the GET param
|
187
|
+
`_no_wrap` is used, it has to forward the request and then wrap the body:
|
188
|
+
|
189
|
+
class Backend
|
190
|
+
def initialize(app); @app = app; end
|
191
|
+
def call(env)
|
192
|
+
if Rack::Request.new(env)['_no_wrap']
|
193
|
+
status, header, body = @app.call(env)
|
194
|
+
res = Rack::Response.new('<!-- ', status, header)
|
195
|
+
if body.respond_to? :to_str
|
196
|
+
res.write body.to_str
|
197
|
+
elsif body.respond_to?(:each)
|
198
|
+
body.each { |part|
|
199
|
+
res.write part.to_s
|
200
|
+
}
|
201
|
+
end
|
202
|
+
res.write(' -->')
|
203
|
+
res.finish
|
204
|
+
else
|
205
|
+
[200, {'Content-Type'=>'text/plain'}, ['not wrapped']]
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
Here, if the param `_no_wrap` is used, this middleware will ask the response to the API middleware
|
211
|
+
and then will create a new Response with the body wrapped between `<!-- ` and ` -->`.
|
212
|
+
|
167
213
|
HOW TO PLUG AN ORM
|
168
214
|
==================
|
169
215
|
|
@@ -204,6 +250,7 @@ CHANGE LOG
|
|
204
250
|
0.0.1 First version
|
205
251
|
0.0.2 Accept CamelCased class names
|
206
252
|
0.0.3 Fix Form mockup
|
253
|
+
0.0.4 Partial available not only via XHR but also via `_no_wrap` param
|
207
254
|
|
208
255
|
COPYRIGHT
|
209
256
|
=========
|
data/lib/backend_api.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
class BackendAPI
|
2
|
-
VERSION = [0,0,
|
2
|
+
VERSION = [0,0,4]
|
3
3
|
WRAP = <<-EOT
|
4
4
|
<!doctype html>
|
5
5
|
<html>
|
@@ -51,7 +51,7 @@ class BackendAPI
|
|
51
51
|
def get
|
52
52
|
@model_instance ||= @model_class.backend_post
|
53
53
|
@model_instance.backend_put @req['model']
|
54
|
-
form = @model_instance.backend_form(@req.path, @req['fields'], :destination => @req['_destination'], :submit_text => @req['_submit_text'] )
|
54
|
+
form = @model_instance.backend_form(@req.path, @req['fields'], :destination => @req['_destination'], :submit_text => @req['_submit_text'], :no_wrap => @req['_no_wrap'])
|
55
55
|
@res.write(wrap_form(form))
|
56
56
|
end
|
57
57
|
|
@@ -102,14 +102,14 @@ class BackendAPI
|
|
102
102
|
@res.redirect(::Rack::Utils::unescape(@req['_destination']))
|
103
103
|
end
|
104
104
|
else
|
105
|
-
form = @model_instance.backend_form(@req.path, @req['model'].keys, :destination => @req['_destination'], :submit_text => @req['_submit_text'])
|
105
|
+
form = @model_instance.backend_form(@req.path, @req['model'].keys, :destination => @req['_destination'], :submit_text => @req['_submit_text'], :no_wrap => @req['_no_wrap'])
|
106
106
|
@res.write(wrap_form(form))
|
107
107
|
@res.status=400 # Bad Request
|
108
108
|
end
|
109
109
|
end
|
110
110
|
|
111
111
|
def wrap_form(form)
|
112
|
-
if @req.xhr?
|
112
|
+
if @req['_no_wrap'] || @req.xhr?
|
113
113
|
form
|
114
114
|
else
|
115
115
|
WRAP % [@model_class_name, form]
|
@@ -27,6 +27,7 @@ module ::Sequel::Plugins::RackBackendApiAdapter
|
|
27
27
|
o << "<input type='hidden' name='_method' value='#{opts[:method] || method}' />\n"
|
28
28
|
o << "<input type='hidden' name='_destination' value='#{opts[:destination]}' />\n" unless opts[:destination].nil?
|
29
29
|
o << "<input type='hidden' name='_submit_text' value='#{opts[:submit_text]}' />\n" unless opts[:submit_text].nil?
|
30
|
+
o << "<input type='hidden' name='_no_wrap' value='#{opts[:no_wrap]}' />\n" unless opts[:no_wrap].nil?
|
30
31
|
o << "<input type='submit' name='save' value='#{opts[:submit_text] || 'SAVE'}' />\n"
|
31
32
|
o << "</form>\n"
|
32
33
|
o
|
data/rack-backend-api.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'rack-backend-api'
|
3
|
-
s.version = "0.0.
|
3
|
+
s.version = "0.0.4"
|
4
4
|
s.platform = Gem::Platform::RUBY
|
5
5
|
s.summary = "A Rack middleware that provides a simple API for your Admin section"
|
6
6
|
s.description = "The purpose of this Rack Middleware is to provide an API that interfaces with database actions in order to build a CMS."
|
data/test/spec_backend_api.rb
CHANGED
@@ -22,6 +22,27 @@ def wrap(title, form) #mock wrapped versions of forms when not XHR
|
|
22
22
|
BackendAPI::WRAP % [title,form]
|
23
23
|
end
|
24
24
|
|
25
|
+
class WrappingMiddleware
|
26
|
+
def initialize(app); @app = app; end
|
27
|
+
def call(env)
|
28
|
+
if Rack::Request.new(env)['_no_wrap']
|
29
|
+
status, header, body = @app.call(env)
|
30
|
+
res = Rack::Response.new('<!-- ', status, header)
|
31
|
+
if body.respond_to? :to_str
|
32
|
+
res.write body.to_str
|
33
|
+
elsif body.respond_to?(:each)
|
34
|
+
body.each { |part|
|
35
|
+
res.write part.to_s
|
36
|
+
}
|
37
|
+
end
|
38
|
+
res.write(' -->')
|
39
|
+
res.finish
|
40
|
+
else
|
41
|
+
[200, {'Content-Type'=>'text/plain'}, ['not wrapped']]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
25
46
|
describe 'API Misc' do
|
26
47
|
should "Send 404 X-cascade if no response at the bottom of the Rack stack - Builder::run" do
|
27
48
|
res = req_lint(BackendAPI.new).get('/zzz')
|
@@ -85,9 +106,16 @@ describe 'API Post' do
|
|
85
106
|
res.headers['Location']=='http://www.domain.com/list.xml'
|
86
107
|
Haiku.order(:id).last.title.should=='Destination Summer'
|
87
108
|
end
|
88
|
-
should "
|
109
|
+
should "Keep _destination until form is validated" do
|
89
110
|
req_lint(BackendAPI.new).post('/haiku', :params => {'_destination' => '/', 'model' => {'title' => '13'}}).body.should.match(/name='_destination'.*value='\/'/)
|
90
111
|
end
|
112
|
+
should "Keep _no_wrap until form is validated" do
|
113
|
+
compared = Haiku.new.set('title' => '13')
|
114
|
+
compared.valid?
|
115
|
+
res = req_lint(WrappingMiddleware.new(BackendAPI.new)).post('/haiku', :params => {'_no_wrap' => 'true', 'model' => {'title' => '13'}})
|
116
|
+
res.body.should==('<!-- '+compared.backend_form('/haiku',['title'], {:no_wrap=>'true'})+' -->')
|
117
|
+
res.body.should.match(/name='_no_wrap'.*value='true'/)
|
118
|
+
end
|
91
119
|
end
|
92
120
|
|
93
121
|
describe 'API Get' do
|
@@ -106,8 +134,10 @@ describe 'API Get' do
|
|
106
134
|
req_lint(BackendAPI.new).get('/haiku', :params => {'model' => update}).body.should==wrap('Haiku', Haiku.new.set(update).backend_form('/haiku'))
|
107
135
|
req_lint(BackendAPI.new).get('/haiku/3', :params => {'model' => update}).body.should==wrap('Haiku', Haiku[3].set(update).backend_form('/haiku/3'))
|
108
136
|
end
|
109
|
-
should "Return a partial if the request is XHR" do
|
137
|
+
should "Return a partial if the request is XHR or param _no_wrap is used" do
|
110
138
|
req_lint(BackendAPI.new).get('/haiku', "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest").body.should==Haiku.new.backend_form('/haiku')
|
139
|
+
req_lint(BackendAPI.new).get('/haiku?_no_wrap=true').body.should==Haiku.new.backend_form('/haiku', nil, {:no_wrap=>'true'})
|
140
|
+
req_lint(WrappingMiddleware.new(BackendAPI.new)).get('/haiku?_no_wrap=true').body.should==('<!-- '+Haiku.new.backend_form('/haiku', nil, {:no_wrap=>'true'})+' -->')
|
111
141
|
end
|
112
142
|
end
|
113
143
|
|
@@ -149,6 +179,13 @@ describe 'API Put' do
|
|
149
179
|
should "keep destination until form is validated" do
|
150
180
|
req_lint(BackendAPI.new).put('/haiku/3', :params => {'_destination' => '/', 'model' => {'title' => '13'}}).body.should.match(/name='_destination'.*value='\/'/)
|
151
181
|
end
|
182
|
+
should "Keep _no_wrap until form is validated" do
|
183
|
+
compared = Haiku[3].set('title' => '13')
|
184
|
+
compared.valid?
|
185
|
+
res = req_lint(WrappingMiddleware.new(BackendAPI.new)).post('/haiku/3', :params => {'_no_wrap' => 'true', 'model' => {'title' => '13'}})
|
186
|
+
res.body.should==('<!-- '+compared.backend_form('/haiku/3',['title'], {:no_wrap=>'true'})+' -->')
|
187
|
+
res.body.should.match(/name='_no_wrap'.*value='true'/)
|
188
|
+
end
|
152
189
|
end
|
153
190
|
|
154
191
|
describe 'API Delete' do
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-backend-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 4
|
10
|
+
version: 0.0.4
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Mickael Riga
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-07-
|
18
|
+
date: 2011-07-21 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|