roar-rails 0.1.6 → 1.0.0

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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.markdown +5 -0
  3. data/Gemfile +1 -1
  4. data/README.markdown +12 -8
  5. data/gemfiles/Gemfile.rails3-0 +2 -0
  6. data/gemfiles/Gemfile.rails3-2 +1 -0
  7. data/lib/roar-rails.rb +4 -6
  8. data/lib/roar/rails/controller_additions.rb +26 -10
  9. data/lib/roar/rails/hal.rb +3 -3
  10. data/lib/roar/rails/railtie.rb +5 -0
  11. data/lib/roar/rails/responder.rb +1 -1
  12. data/lib/roar/rails/validations_representer.rb +3 -3
  13. data/lib/roar/rails/version.rb +1 -1
  14. data/roar-rails.gemspec +3 -3
  15. data/test/consume_test.rb +64 -2
  16. data/test/dummy/app/representers/band_representer.rb +2 -2
  17. data/test/dummy/app/representers/singer_alias_representer.rb +1 -1
  18. data/test/dummy/app/representers/singer_representer.rb +2 -2
  19. data/test/json_hal_renderer_test.rb +5 -13
  20. data/test/render_test.rb +1 -1
  21. data/test/responder_test.rb +44 -5
  22. data/test/test_helper.rb +9 -0
  23. metadata +66 -52
  24. data/test/dummy/Rakefile +0 -7
  25. data/test/dummy/app/helpers/application_helper.rb +0 -2
  26. data/test/dummy/app/views/layouts/application.html.erb +0 -14
  27. data/test/dummy/app/views/musician/featured.html.erb +0 -1
  28. data/test/dummy/app/views/musician/featured_with_block.html.erb +0 -4
  29. data/test/dummy/app/views/musician/hamlet.html.haml +0 -1
  30. data/test/dummy/config/locales/en.yml +0 -5
  31. data/test/dummy/public/404.html +0 -26
  32. data/test/dummy/public/422.html +0 -26
  33. data/test/dummy/public/500.html +0 -26
  34. data/test/dummy/public/favicon.ico +0 -0
  35. data/test/dummy/public/javascripts/application.js +0 -2
  36. data/test/dummy/public/javascripts/controls.js +0 -965
  37. data/test/dummy/public/javascripts/dragdrop.js +0 -974
  38. data/test/dummy/public/javascripts/effects.js +0 -1123
  39. data/test/dummy/public/javascripts/prototype.js +0 -4874
  40. data/test/dummy/public/javascripts/rails.js +0 -118
  41. data/test/dummy/public/stylesheets/.gitkeep +0 -0
  42. data/test/dummy/script/rails +0 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7fbf7c943c30c7284ff2cf46861318701910e138
4
- data.tar.gz: e6e6cb5e5816418c71c75d023bbfc61dc4551def
3
+ metadata.gz: 1dbecd0bbc7e521087763fd2ff0313d7d3cda940
4
+ data.tar.gz: 3b14e95c24d51ee0003f97c4c079dafc62a40699
5
5
  SHA512:
6
- metadata.gz: 45631ddc9bfc4f96279e7b1f7538cf33473cf5f6cc5f5cb1abafb4b5b7a149a65e5ec67f95c25c63510821898c9a47d6c7b86aec31270399dbd821bb343339c0
7
- data.tar.gz: 5d20060c50ce90161bbd93ee41c81cb71e5544ad04c32e428dbf556e69b1d32153f63d7f5c1e5631d7db9bf6f60216d9286ea511cd6a955f35e6ceef4b57dca8
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
@@ -4,7 +4,7 @@ source "http://rubygems.org"
4
4
  gemspec
5
5
 
6
6
  group :test do
7
- #gem 'roar', path: "../roar" #">= 0.11.17"
7
+ # gem 'roar', path: "../roar" #">= 0.11.17"
8
8
  #gem 'representable', path: "../representable"
9
9
  gem 'rake', '10.1.0'
10
10
  end
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::Representer::JSON
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
- The `consume!` call will roughly do the following.
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
- from_json(request.body)
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
- Note that it respects settings from `#represents`. It uses the same mechanics known from `#respond_with` to choose a representer.
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::Representer::JSON
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::Representer::JSON
215
- include Roar::Representer::Feature::Hypermedia
218
+ include Roar::JSON
219
+ include Roar::Hypermedia
216
220
 
217
221
  link :self do
218
222
  fruit_url self
@@ -5,3 +5,5 @@ gemspec :path => '../'
5
5
 
6
6
  gem 'railties', '~> 3.0.11'
7
7
  gem 'activerecord', '~> 3.0.11'
8
+ gem 'minitest', '4.7.5'
9
+
@@ -6,3 +6,4 @@ gemspec :path => '../'
6
6
 
7
7
  gem 'railties', '~> 3.2.13'
8
8
  gem 'activerecord', '~> 3.2.13'
9
+ gem 'minitest', '4.7.5'
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::Representer
7
- autoload("XML", "roar/representer/xml")
8
- autoload("JSON", "roar/representer/json")
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
- module Feature
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
- format = formats.first # FIXME: i expected request.content_mime_type to do the job. copied from responder.rb. this will return the wrong format when the controller responds to :json and :xml and the Content-type is :xml (?)
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(compute_parsing_method(format), incoming_string, options) # e.g. from_json("...")
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
- def render_to_body(options)
56
- if res = options[formats.first] and res.is_a?(Roar::Rails::Responder::Response)
57
- response.content_type = res.content_type
58
- return res.body
59
- end
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
- super
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
- end
86
+
87
+ class UnsupportedMediaType < StandardError #:nodoc:
88
+ end
89
+ end
@@ -1,6 +1,6 @@
1
- require 'roar/representer/json/hal'
1
+ require 'roar/json/hal'
2
2
 
3
- Roar::Representer::JSON::HAL.class_eval do
3
+ Roar::JSON::HAL.class_eval do
4
4
  def to_hal(*args); to_json(*args); end
5
5
  def from_hal(*args); from_json(*args); end
6
- end
6
+ end
@@ -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
@@ -69,4 +69,4 @@ module Roar
69
69
  end
70
70
  end
71
71
  end
72
- end
72
+ end
@@ -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::Representer::JSON
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
@@ -1,5 +1,5 @@
1
1
  module Roar
2
2
  module Rails
3
- VERSION = "0.1.6"
3
+ VERSION = "1.0.0"
4
4
  end
5
5
  end
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.11.13"
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", "~> 4.0"
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
- post :consume_json, "{\"name\": \"Bumi\"}", :format => 'json'
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::Representer::JSON
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,6 +1,6 @@
1
1
  class BandRepresenter < Roar::Decorator
2
- include Roar::Representer::JSON
3
- include Roar::Representer::Feature::Hypermedia
2
+ include Roar::JSON
3
+ include Roar::Hypermedia
4
4
 
5
5
  property :name
6
6
 
@@ -1,5 +1,5 @@
1
1
  module SingerAliasRepresenter
2
- include Roar::Representer::JSON
2
+ include Roar::JSON
3
3
 
4
4
  property :name, :as => :alias
5
5
 
@@ -1,6 +1,6 @@
1
1
  module SingerRepresenter
2
- include Roar::Representer::JSON
3
- include Roar::Representer::Feature::Hypermedia
2
+ include Roar::JSON
3
+ include Roar::Hypermedia
4
4
 
5
5
  property :name
6
6
 
@@ -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::Representer::JSON::HAL
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+hal request" do
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+hal" do
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+hal'
32
+ assert_equal response.content_type, 'application/hal+json'
41
33
  end
42
- end
34
+ end
data/test/render_test.rb CHANGED
@@ -5,7 +5,7 @@ class RenderTest < ActionController::TestCase
5
5
 
6
6
  class SingersController < ActionController::Base
7
7
  module SingerRepresenter
8
- include Roar::Representer::JSON
8
+ include Roar::JSON
9
9
 
10
10
  property :name, :as => :title
11
11
  end