roar-rails 0.1.6 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.markdown +5 -0
- data/Gemfile +1 -1
- data/README.markdown +12 -8
- data/gemfiles/Gemfile.rails3-0 +2 -0
- data/gemfiles/Gemfile.rails3-2 +1 -0
- data/lib/roar-rails.rb +4 -6
- data/lib/roar/rails/controller_additions.rb +26 -10
- data/lib/roar/rails/hal.rb +3 -3
- data/lib/roar/rails/railtie.rb +5 -0
- data/lib/roar/rails/responder.rb +1 -1
- data/lib/roar/rails/validations_representer.rb +3 -3
- data/lib/roar/rails/version.rb +1 -1
- data/roar-rails.gemspec +3 -3
- data/test/consume_test.rb +64 -2
- data/test/dummy/app/representers/band_representer.rb +2 -2
- data/test/dummy/app/representers/singer_alias_representer.rb +1 -1
- data/test/dummy/app/representers/singer_representer.rb +2 -2
- data/test/json_hal_renderer_test.rb +5 -13
- data/test/render_test.rb +1 -1
- data/test/responder_test.rb +44 -5
- data/test/test_helper.rb +9 -0
- metadata +66 -52
- data/test/dummy/Rakefile +0 -7
- data/test/dummy/app/helpers/application_helper.rb +0 -2
- data/test/dummy/app/views/layouts/application.html.erb +0 -14
- data/test/dummy/app/views/musician/featured.html.erb +0 -1
- data/test/dummy/app/views/musician/featured_with_block.html.erb +0 -4
- data/test/dummy/app/views/musician/hamlet.html.haml +0 -1
- data/test/dummy/config/locales/en.yml +0 -5
- data/test/dummy/public/404.html +0 -26
- data/test/dummy/public/422.html +0 -26
- data/test/dummy/public/500.html +0 -26
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/public/javascripts/application.js +0 -2
- data/test/dummy/public/javascripts/controls.js +0 -965
- data/test/dummy/public/javascripts/dragdrop.js +0 -974
- data/test/dummy/public/javascripts/effects.js +0 -1123
- data/test/dummy/public/javascripts/prototype.js +0 -4874
- data/test/dummy/public/javascripts/rails.js +0 -118
- data/test/dummy/public/stylesheets/.gitkeep +0 -0
- data/test/dummy/script/rails +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1dbecd0bbc7e521087763fd2ff0313d7d3cda940
|
4
|
+
data.tar.gz: 3b14e95c24d51ee0003f97c4c079dafc62a40699
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0bcfc77fe5ff9d9e0fdb48d962bad6ffd2f44fcbd7446d31b4fbf3f1c14bbadad93ead2356103024f2923d0d1104f0317c93398d5ede28b5e5beaa499d4b30d8
|
7
|
+
data.tar.gz: 87b69c8d04bfbf819c32b0bbe2dca74ac929d374f315837a87d449a76656eaf2b0ba090ef93b605bfeaa0579c34f91070c768f3f886be9e1902059dffebeb73c
|
data/CHANGES.markdown
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
## 1.0.0
|
2
|
+
|
3
|
+
* Requires Roar >= 1.0.0.
|
4
|
+
* In `#consume!` roar-rails now finds the correct representer for the `Content-type:` header. In former version the representer name was infered using the `Accept:` header, which was totally wrong. Thanks to @pgaertig for fixing that.
|
5
|
+
|
1
6
|
## 0.1.6
|
2
7
|
|
3
8
|
* Added `ControllerAdditions::Render` to support `#render` in controller actions with representers.
|
data/Gemfile
CHANGED
data/README.markdown
CHANGED
@@ -32,7 +32,7 @@ This will create the file `app/representers/band_representer.rb` with the follow
|
|
32
32
|
|
33
33
|
```ruby
|
34
34
|
module BandRepresenter
|
35
|
-
include Roar::
|
35
|
+
include Roar::JSON
|
36
36
|
|
37
37
|
property :id
|
38
38
|
property :name
|
@@ -129,6 +129,7 @@ end
|
|
129
129
|
## Parsing incoming documents
|
130
130
|
|
131
131
|
In `#create` and `#update` actions it is often necessary to parse the incoming representation and map it to a model instance. Use the `#consume!` method for this.
|
132
|
+
The client must provide a `Content-Type` request header with proper MIME type to let `#consume!` know which representer to use.
|
132
133
|
|
133
134
|
```ruby
|
134
135
|
class SingersController < ApplicationController
|
@@ -143,17 +144,20 @@ class SingersController < ApplicationController
|
|
143
144
|
end
|
144
145
|
```
|
145
146
|
|
146
|
-
|
147
|
+
For instance, if content type is set to `application/xml` the `consume!` call will roughly do the following.
|
147
148
|
|
148
149
|
```ruby
|
149
150
|
singer.
|
150
151
|
extend(SingerRepresenter)
|
151
|
-
|
152
|
+
from_xml(request.body)
|
152
153
|
```
|
153
154
|
|
154
|
-
So, `#consume!` helps you figuring out the representer module and reading the incoming document.
|
155
|
+
So, `#consume!` helps you figuring out the representer module and reading the incoming document. Just like Rails, depending on the registered MIME type for `Content-type` it picks the deserialize method (e.g. `from_json` vs. `from_xml`)
|
155
156
|
|
156
|
-
|
157
|
+
It is important to provide a known content type in the request. If it is missing or not supported by the responder
|
158
|
+
`#consume!` will raise an exception `Roar::Rails::ControllerAdditions::UnsupportedMediaType`. Unless you rescue the exception the action will stop and respond with HTTP status `406 Unsupported Media Type`.
|
159
|
+
|
160
|
+
Note that `#consume!` respects settings from `#represents`. It uses the same mechanics known from `#respond_with` to choose a representer.
|
157
161
|
|
158
162
|
```ruby
|
159
163
|
consume!(singer, :represent_with => MusicianRepresenter)
|
@@ -165,7 +169,7 @@ If you prefer roar's decorator approach over extend, just go for it. roar-rails
|
|
165
169
|
|
166
170
|
```ruby
|
167
171
|
class SingerRepresenter < Roar::Decorator
|
168
|
-
include Roar::
|
172
|
+
include Roar::JSON
|
169
173
|
|
170
174
|
property :name
|
171
175
|
|
@@ -211,8 +215,8 @@ Any URL helpers from the Rails app are automatically available in representers.
|
|
211
215
|
|
212
216
|
```ruby
|
213
217
|
module FruitRepresenter
|
214
|
-
include Roar::
|
215
|
-
include Roar::
|
218
|
+
include Roar::JSON
|
219
|
+
include Roar::Hypermedia
|
216
220
|
|
217
221
|
link :self do
|
218
222
|
fruit_url self
|
data/gemfiles/Gemfile.rails3-0
CHANGED
data/gemfiles/Gemfile.rails3-2
CHANGED
data/lib/roar-rails.rb
CHANGED
@@ -3,17 +3,15 @@ require "roar/representer"
|
|
3
3
|
require "roar/decorator"
|
4
4
|
require "roar/rails/railtie"
|
5
5
|
|
6
|
-
module Roar
|
7
|
-
autoload("XML", "roar/
|
8
|
-
autoload("JSON", "roar/
|
6
|
+
module Roar
|
7
|
+
autoload("XML", "roar/xml")
|
8
|
+
autoload("JSON", "roar/json")
|
9
9
|
|
10
10
|
module JSON
|
11
11
|
autoload("HAL", "roar/rails/hal")
|
12
12
|
end
|
13
13
|
|
14
|
-
|
15
|
-
autoload("Hypermedia", "roar/representer/feature/hypermedia")
|
16
|
-
end
|
14
|
+
autoload("Hypermedia", "roar/hypermedia")
|
17
15
|
end
|
18
16
|
|
19
17
|
|
@@ -17,17 +17,22 @@ module Roar::Rails
|
|
17
17
|
|
18
18
|
module ClassMethods
|
19
19
|
def represents(format, options)
|
20
|
-
represents_options.add(format,options)
|
20
|
+
represents_options.add(format, options)
|
21
21
|
respond_to format
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
25
|
|
26
|
+
# TODO: move into separate class so we don't pollute controller.
|
26
27
|
def consume!(model, options={})
|
27
|
-
|
28
|
+
content_type = request.content_type
|
29
|
+
|
30
|
+
format = Mime::Type.lookup(content_type).try(:symbol) or raise UnsupportedMediaType.new("Cannot consume unregistered media type '#{content_type.inspect}'")
|
31
|
+
|
32
|
+
parsing_method = compute_parsing_method(format)
|
28
33
|
representer = prepare_model_for(format, model, options)
|
29
34
|
|
30
|
-
representer.send(
|
35
|
+
representer.send(parsing_method, incoming_string, options) # e.g. from_json("...")
|
31
36
|
model
|
32
37
|
end
|
33
38
|
|
@@ -52,15 +57,23 @@ module Roar::Rails
|
|
52
57
|
body.read
|
53
58
|
end
|
54
59
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
+
# These methods deal with interfacing between the Roar Response object and
|
61
|
+
# ActionController, they simply pass the body of the Roar response up or do nothing
|
62
|
+
def _render_option_json(resource, options)
|
63
|
+
super(_resource_or_body(resource), options)
|
64
|
+
end
|
60
65
|
|
61
|
-
|
66
|
+
def _render_option_xml(resource, options)
|
67
|
+
super(_resource_or_body(resource), options)
|
62
68
|
end
|
63
69
|
|
70
|
+
def _render_option_hal(resource, options)
|
71
|
+
super(_resource_or_body(resource), options)
|
72
|
+
end
|
73
|
+
|
74
|
+
def _resource_or_body(resource)
|
75
|
+
resource.is_a?(Roar::Rails::Responder::Response) ? resource.body : resource
|
76
|
+
end
|
64
77
|
|
65
78
|
# Include if you intend to use roar-rails with <tt>render json: model</tt>.
|
66
79
|
module Render
|
@@ -70,4 +83,7 @@ module Roar::Rails
|
|
70
83
|
end
|
71
84
|
end
|
72
85
|
end
|
73
|
-
|
86
|
+
|
87
|
+
class UnsupportedMediaType < StandardError #:nodoc:
|
88
|
+
end
|
89
|
+
end
|
data/lib/roar/rails/hal.rb
CHANGED
data/lib/roar/rails/railtie.rb
CHANGED
@@ -6,6 +6,11 @@ module Roar
|
|
6
6
|
class Railtie < ::Rails::Railtie
|
7
7
|
config.representer = ActiveSupport::OrderedOptions.new
|
8
8
|
|
9
|
+
rescue_responses = config.action_dispatch.rescue_responses || ActionDispatch::ShowExceptions.rescue_responses #newer or fallback to 3.0
|
10
|
+
rescue_responses.merge!(
|
11
|
+
'Roar::Rails::ControllerAdditions::UnsupportedMediaType' => :unsupported_media_type
|
12
|
+
)
|
13
|
+
|
9
14
|
initializer "roar.set_configs" do |app|
|
10
15
|
::Roar::Representer.module_eval do
|
11
16
|
include app.routes.url_helpers
|
data/lib/roar/rails/responder.rb
CHANGED
@@ -6,14 +6,14 @@ module ValidatorsRepresenter
|
|
6
6
|
class ValidatorClient
|
7
7
|
attr_accessor :kind, :options
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
# Represents a single Validator instance.
|
11
11
|
module ValidatorRepresenter
|
12
|
-
include Roar::
|
12
|
+
include Roar::JSON
|
13
13
|
property :kind
|
14
14
|
hash :options
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
# Represents an array of validators for an attribute.
|
18
18
|
module AttributeValidators
|
19
19
|
include Representable::JSON::Collection
|
data/lib/roar/rails/version.rb
CHANGED
data/roar-rails.gemspec
CHANGED
@@ -18,13 +18,13 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
19
|
s.require_paths = ["lib"]
|
20
20
|
|
21
|
-
s.add_runtime_dependency "roar", ">= 0.
|
21
|
+
s.add_runtime_dependency "roar", ">= 1.0.0", "<= 1.1.0"
|
22
22
|
s.add_runtime_dependency "test_xml", ">= 0.1.6" # TODO: remove dependency as most people don't use XML.
|
23
23
|
s.add_runtime_dependency "actionpack"
|
24
24
|
s.add_runtime_dependency "railties", ">= 3.0.0"
|
25
|
-
s.add_runtime_dependency "uber"
|
25
|
+
s.add_runtime_dependency "uber", ">= 0.0.5"
|
26
26
|
|
27
|
-
s.add_development_dependency "minitest"
|
27
|
+
s.add_development_dependency "minitest"
|
28
28
|
s.add_development_dependency "activemodel"
|
29
29
|
s.add_development_dependency "activerecord"
|
30
30
|
s.add_development_dependency "sqlite3"
|
data/test/consume_test.rb
CHANGED
@@ -16,16 +16,33 @@ class ConsumeTest < ActionController::TestCase
|
|
16
16
|
tests UnnamespaceSingersController
|
17
17
|
|
18
18
|
test "#consume parses incoming document and updates the model" do
|
19
|
-
|
19
|
+
@request.env['CONTENT_TYPE'] = 'application/json'
|
20
|
+
post :consume_json, "{\"name\": \"Bumi\"}"
|
20
21
|
assert_equal %{#<struct Singer name="Bumi">}, @response.body
|
21
22
|
end
|
22
23
|
end
|
23
24
|
|
25
|
+
class ConsumeHalWithNoHalRespondTest < ActionController::TestCase
|
26
|
+
include Roar::Rails::TestCase
|
27
|
+
|
28
|
+
tests UnnamespaceSingersController
|
29
|
+
|
30
|
+
# Content-type is set properly, it's a registered mime but responder doesn't do #from_hal.
|
31
|
+
# FIXME: why does that still find a representer?
|
32
|
+
test "#consume parses hal document and updates the model" do
|
33
|
+
@request.env['CONTENT_TYPE'] = 'application/hal+json'
|
34
|
+
# assert_raises Roar::Rails::UnsupportedMediaType do
|
35
|
+
assert_raises NoMethodError do # currently, we don't know if a format is supported in general, or not.
|
36
|
+
post :consume_json, "{\"name\": \"Bumi\"}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
24
41
|
class ConsumeWithConfigurationTest < ActionController::TestCase
|
25
42
|
include Roar::Rails::TestCase
|
26
43
|
|
27
44
|
module MusicianRepresenter
|
28
|
-
include Roar::
|
45
|
+
include Roar::JSON
|
29
46
|
property :name, :as => :called
|
30
47
|
end
|
31
48
|
|
@@ -44,9 +61,52 @@ class ConsumeWithConfigurationTest < ActionController::TestCase
|
|
44
61
|
tests SingersController
|
45
62
|
|
46
63
|
test "#consume uses ConsumeWithConfigurationTest::MusicianRepresenter to parse incoming document" do
|
64
|
+
@request.env['CONTENT_TYPE'] = 'application/json'
|
47
65
|
post :consume_json, %{{"called":"Bumi"}}, :format => :json
|
48
66
|
assert_equal %{#<struct Singer name="Bumi">}, @response.body
|
49
67
|
end
|
68
|
+
|
69
|
+
test "#do not consume missing content type" do
|
70
|
+
assert_raises Roar::Rails::UnsupportedMediaType do
|
71
|
+
post :consume_json, "{\"name\": \"Bumi\"}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
test "#do not consume parses unknown content type" do
|
77
|
+
@request.env['CONTENT_TYPE'] = 'application/custom+json'
|
78
|
+
assert_raises Roar::Rails::UnsupportedMediaType do
|
79
|
+
post :consume_json, "{\"name\": \"Bumi\"}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class ConsumeHalTest < ActionController::TestCase
|
85
|
+
include Roar::Rails::TestCase
|
86
|
+
|
87
|
+
module MusicianRepresenter
|
88
|
+
include Roar::JSON::HAL
|
89
|
+
property :name
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
class SingersController < ActionController::Base
|
94
|
+
include Roar::Rails::ControllerAdditions
|
95
|
+
represents :hal, :entity => MusicianRepresenter
|
96
|
+
|
97
|
+
def consume_hal
|
98
|
+
singer = consume!(Singer.new)
|
99
|
+
render :text => singer.inspect
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
tests SingersController
|
104
|
+
|
105
|
+
test "#consume parses HAL document and updates the model" do
|
106
|
+
@request.env['CONTENT_TYPE'] = 'application/hal+json'
|
107
|
+
post :consume_hal, "{\"name\": \"Bumi\"}"
|
108
|
+
assert_equal %{#<struct Singer name="Bumi">}, @response.body
|
109
|
+
end
|
50
110
|
end
|
51
111
|
|
52
112
|
class ConsumeWithOptionsOverridingConfigurationTest < ActionController::TestCase
|
@@ -66,6 +126,7 @@ class ConsumeWithOptionsOverridingConfigurationTest < ActionController::TestCase
|
|
66
126
|
tests SingersController
|
67
127
|
|
68
128
|
test "#consume uses #represents config to parse incoming document" do
|
129
|
+
@request.env['CONTENT_TYPE'] = 'application/json'
|
69
130
|
post :consume_json, %{{"called":"Bumi"}}, :format => :json
|
70
131
|
assert_equal %{#<struct Singer name="Bumi">}, @response.body
|
71
132
|
end
|
@@ -73,6 +134,7 @@ end
|
|
73
134
|
|
74
135
|
class RequestBodyStringTest < ConsumeTest
|
75
136
|
test "#read rewinds before reading" do
|
137
|
+
@request.env['CONTENT_TYPE'] = 'application/json'
|
76
138
|
@request.instance_eval do
|
77
139
|
def body
|
78
140
|
incoming = super
|
@@ -1,19 +1,11 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
Mime::Type.register 'application/json+hal', :hal
|
4
|
-
if Roar::Rails.rails_version >= 4.1
|
5
|
-
ActionController.add_renderer :hal do |js, options|
|
6
|
-
self.content_type ||= Mime::HAL
|
7
|
-
js.to_json
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
3
|
class HalRendererTest < ActionController::TestCase
|
12
4
|
include Roar::Rails::TestCase
|
13
5
|
|
14
6
|
class SingersController < ActionController::Base
|
15
7
|
module HalSingerRepresenter
|
16
|
-
include Roar::
|
8
|
+
include Roar::JSON::HAL
|
17
9
|
|
18
10
|
property :name
|
19
11
|
link(:self) { "http://#{name}" }
|
@@ -30,13 +22,13 @@ class HalRendererTest < ActionController::TestCase
|
|
30
22
|
|
31
23
|
tests SingersController
|
32
24
|
|
33
|
-
test "should render correctly in response to a application/json
|
25
|
+
test "should render correctly in response to a application/hal+json request" do
|
34
26
|
get :show, :id => "bumi", :format => :hal
|
35
27
|
assert_body '{"name":"Bumi","_links":{"self":{"href":"http://Bumi"}}}'
|
36
28
|
end
|
37
29
|
|
38
|
-
test "should have a content_type of application/json
|
30
|
+
test "should have a content_type of application/hal+json" do
|
39
31
|
get :show, :id => "bumi", :format => :hal
|
40
|
-
assert_equal response.content_type, 'application/json
|
32
|
+
assert_equal response.content_type, 'application/hal+json'
|
41
33
|
end
|
42
|
-
end
|
34
|
+
end
|