Skip to content

Commit 1aa64f2

Browse files
committed
Merge pull request #1550 from remear/url-helpers
Add Rails url_helpers
2 parents 3ba5254 + cc10928 commit 1aa64f2

File tree

15 files changed

+177
-52
lines changed

15 files changed

+177
-52
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
Breaking changes:
44

55
Features:
6+
- [#1550](https://github.com/rails-api/active_model_serializers/pull/1550) Add
7+
Rails url_helpers to `SerializationContext` for use in links. (@remear, @bf4)
68
- [#1004](https://github.com/rails-api/active_model_serializers/pull/1004) JSON API errors object implementation.
79
- Only implements `detail` and `source` as derived from `ActiveModel::Error`
810
- Provides checklist of remaining questions and remaining parts of the spec.

Rakefile

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -45,25 +45,23 @@ Rake::TestTask.new do |t|
4545
end
4646

4747
desc 'Run isolated tests'
48-
task isolated: ['test:isolated:railtie']
48+
task isolated: ['test:isolated']
4949
namespace :test do
50-
namespace :isolated do
50+
task :isolated do
5151
desc 'Run isolated tests for Railtie'
52-
task :railtie do
53-
require 'shellwords'
54-
dir = File.dirname(__FILE__)
55-
file = Shellwords.shellescape("#{dir}/test/active_model_serializers/railtie_test_isolated.rb")
56-
dir = Shellwords.shellescape(dir)
57-
58-
# https://github.com/rails/rails/blob/3d590add45/railties/lib/rails/generators/app_base.rb#L345-L363
59-
_bundle_command = Gem.bin_path('bundler', 'bundle')
60-
require 'bundler'
61-
Bundler.with_clean_env do
62-
command = "-w -I#{dir}/lib -I#{dir}/test #{file}"
52+
require 'shellwords'
53+
dir = File.dirname(__FILE__)
54+
dir = Shellwords.shellescape(dir)
55+
isolated_test_files = FileList['test/**/*_test_isolated.rb']
56+
# https://github.com/rails/rails/blob/3d590add45/railties/lib/rails/generators/app_base.rb#L345-L363
57+
_bundle_command = Gem.bin_path('bundler', 'bundle')
58+
require 'bundler'
59+
Bundler.with_clean_env do
60+
isolated_test_files.all? do |test_file|
61+
command = "-w -I#{dir}/lib -I#{dir}/test #{Shellwords.shellescape(test_file)}"
6362
full_command = %("#{Gem.ruby}" #{command})
64-
system(full_command) or # rubocop:disable Style/AndOr
65-
fail 'Failures'
66-
end
63+
system(full_command)
64+
end or fail 'Failures' # rubocop:disable Style/AndOr
6765
end
6866
end
6967
end

docs/general/getting_started.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,12 @@ class PostsController < ApplicationController
9696

9797
end
9898
```
99+
100+
If you wish to use Rails url helpers for link generation, e.g., `link(:resources) { resources_url }`, ensure your application sets
101+
`Rails.application.routes.default_url_options`.
102+
103+
```ruby
104+
Rails.application.routes.default_url_options = {
105+
host: 'example.com'
106+
}
107+
```

docs/general/rendering.md

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,10 @@ PR please :)
103103

104104
#### links
105105

106-
##### How to add top-level links
106+
If you wish to use Rails url helpers for link generation, e.g., `link(:resources) { resources_url }`, ensure your application sets
107+
`Rails.application.routes.default_url_options`.
108+
109+
##### Top-level
107110

108111
JsonApi supports a [links object](http://jsonapi.org/format/#document-links) to be specified at top-level, that you can specify in the `render`:
109112

@@ -144,6 +147,33 @@ That's the result:
144147

145148
This feature is specific to JsonApi, so you have to use the use the [JsonApi Adapter](adapters.md#jsonapi)
146149

150+
151+
##### Resource-level
152+
153+
In your serializer, define each link in one of the following methods:
154+
155+
As a static string
156+
157+
```ruby
158+
link :link_name, 'https://example.com/resource'
159+
```
160+
161+
As a block to be evaluated. When using Rails, URL helpers are available.
162+
Ensure your application sets `Rails.application.routes.default_url_options`.
163+
164+
```ruby
165+
link :link_name_ do
166+
"https://example.com/resource/#{object.id}"
167+
end
168+
169+
link(:link_name) { "https://example.com/resource/#{object.id}" }
170+
171+
link(:link_name) { resource_url(object) }
172+
173+
link(:link_name) { url_for(controller: 'controller_name', action: 'index', only_path: false) }
174+
175+
```
176+
147177
### serializer_opts
148178

149179
#### include

docs/general/serializers.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,13 +135,15 @@ With the `:json_api` adapter, the previous serializers would be rendered as:
135135

136136
#### ::link
137137

138-
e.g.
139-
140138
```ruby
141-
link :other, 'https://example.com/resource'
142139
link :self do
143-
href "https://example.com/link_author/#{object.id}"
140+
href "https://example.com/link_author/#{object.id}"
144141
end
142+
link :author { link_author_url(object) }
143+
link :link_authors { link_authors_url }
144+
link :other, 'https://example.com/resource'
145+
link :posts { link_author_posts_url(object) }
146+
```
145147
```
146148
147149
#### #object

lib/active_model/serializer/links.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@ def inherited(base)
2020

2121
# Define a link on a serializer.
2222
# @example
23-
# link :self { "//example.com/posts/#{object.id}" }
23+
# link(:self) { resource_url(object) }
2424
# @example
25-
# link :self, "//example.com/user"
25+
# link(:self) { "http://example.com/resource/#{object.id}" }
26+
# @example
27+
# link :resource, "http://example.com/resource"
2628
#
2729
def link(name, value = nil, &block)
2830
_links[name] = block || value

lib/active_model_serializers/adapter/json_api/link.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1+
require 'active_support/core_ext/module/delegation'
2+
13
module ActiveModelSerializers
24
module Adapter
35
class JsonApi
46
class Link
7+
include SerializationContext.url_helpers
8+
delegate :default_url_options, to: SerializationContext
9+
510
def initialize(serializer, value)
611
@object = serializer.object
712
@scope = serializer.scope

lib/active_model_serializers/railtie.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ class Railtie < Rails::Railtie
1515
end
1616
end
1717

18+
initializer 'active_model_serializers.prepare_serialization_context' do
19+
SerializationContext.url_helpers = Rails.application.routes.url_helpers
20+
SerializationContext.default_url_options = Rails.application.routes.default_url_options
21+
end
22+
1823
# This hook is run after the action_controller railtie has set the configuration
1924
# based on the *environment* configuration and before any config/initializers are run
2025
# and also before eager_loading (if enabled).
Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,24 @@
11
module ActiveModelSerializers
22
class SerializationContext
3+
class << self
4+
attr_writer :url_helpers, :default_url_options
5+
end
6+
37
attr_reader :request_url, :query_parameters
48

5-
def initialize(request)
9+
def initialize(request, options = {})
610
@request_url = request.original_url[/\A[^?]+/]
711
@query_parameters = request.query_parameters
12+
@url_helpers = options.delete(:url_helpers) || self.class.url_helpers
13+
@default_url_options = options.delete(:default_url_options) || self.class.default_url_options
14+
end
15+
16+
def self.url_helpers
17+
@url_helpers ||= Module.new
18+
end
19+
20+
def self.default_url_options
21+
@default_url_options ||= {}
822
end
923
end
1024
end

test/active_model_serializers/railtie_test_isolated.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ class WithRails < RailtieTest
1818
"ActionController::Serialization should be included in ActionController::Base, but isn't"
1919
end
2020

21+
test 'prepares url_helpers for SerializationContext' do
22+
assert ActiveModelSerializers::SerializationContext.url_helpers.respond_to? :url_for
23+
assert_equal Rails.application.routes.default_url_options,
24+
ActiveModelSerializers::SerializationContext.default_url_options
25+
end
26+
2127
test 'sets the ActiveModelSerializers.logger to Rails.logger' do
2228
refute_nil Rails.logger
2329
refute_nil ActiveModelSerializers.logger

0 commit comments

Comments
 (0)