mirror of
https://github.com/ditkrg/active_model_serializers.git
synced 2026-01-22 22:06:50 +00:00
Provide Rails url_helpers via SerializationContext
This commit is contained in:
parent
3ba5254a46
commit
cc10928472
@ -3,6 +3,8 @@
|
|||||||
Breaking changes:
|
Breaking changes:
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
- [#1550](https://github.com/rails-api/active_model_serializers/pull/1550) Add
|
||||||
|
Rails url_helpers to `SerializationContext` for use in links. (@remear, @bf4)
|
||||||
- [#1004](https://github.com/rails-api/active_model_serializers/pull/1004) JSON API errors object implementation.
|
- [#1004](https://github.com/rails-api/active_model_serializers/pull/1004) JSON API errors object implementation.
|
||||||
- Only implements `detail` and `source` as derived from `ActiveModel::Error`
|
- Only implements `detail` and `source` as derived from `ActiveModel::Error`
|
||||||
- Provides checklist of remaining questions and remaining parts of the spec.
|
- Provides checklist of remaining questions and remaining parts of the spec.
|
||||||
|
|||||||
16
Rakefile
16
Rakefile
@ -45,25 +45,23 @@ Rake::TestTask.new do |t|
|
|||||||
end
|
end
|
||||||
|
|
||||||
desc 'Run isolated tests'
|
desc 'Run isolated tests'
|
||||||
task isolated: ['test:isolated:railtie']
|
task isolated: ['test:isolated']
|
||||||
namespace :test do
|
namespace :test do
|
||||||
namespace :isolated do
|
task :isolated do
|
||||||
desc 'Run isolated tests for Railtie'
|
desc 'Run isolated tests for Railtie'
|
||||||
task :railtie do
|
|
||||||
require 'shellwords'
|
require 'shellwords'
|
||||||
dir = File.dirname(__FILE__)
|
dir = File.dirname(__FILE__)
|
||||||
file = Shellwords.shellescape("#{dir}/test/active_model_serializers/railtie_test_isolated.rb")
|
|
||||||
dir = Shellwords.shellescape(dir)
|
dir = Shellwords.shellescape(dir)
|
||||||
|
isolated_test_files = FileList['test/**/*_test_isolated.rb']
|
||||||
# https://github.com/rails/rails/blob/3d590add45/railties/lib/rails/generators/app_base.rb#L345-L363
|
# https://github.com/rails/rails/blob/3d590add45/railties/lib/rails/generators/app_base.rb#L345-L363
|
||||||
_bundle_command = Gem.bin_path('bundler', 'bundle')
|
_bundle_command = Gem.bin_path('bundler', 'bundle')
|
||||||
require 'bundler'
|
require 'bundler'
|
||||||
Bundler.with_clean_env do
|
Bundler.with_clean_env do
|
||||||
command = "-w -I#{dir}/lib -I#{dir}/test #{file}"
|
isolated_test_files.all? do |test_file|
|
||||||
|
command = "-w -I#{dir}/lib -I#{dir}/test #{Shellwords.shellescape(test_file)}"
|
||||||
full_command = %("#{Gem.ruby}" #{command})
|
full_command = %("#{Gem.ruby}" #{command})
|
||||||
system(full_command) or # rubocop:disable Style/AndOr
|
system(full_command)
|
||||||
fail 'Failures'
|
end or fail 'Failures' # rubocop:disable Style/AndOr
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -96,3 +96,12 @@ class PostsController < ApplicationController
|
|||||||
|
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If you wish to use Rails url helpers for link generation, e.g., `link(:resources) { resources_url }`, ensure your application sets
|
||||||
|
`Rails.application.routes.default_url_options`.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
Rails.application.routes.default_url_options = {
|
||||||
|
host: 'example.com'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@ -103,7 +103,10 @@ PR please :)
|
|||||||
|
|
||||||
#### links
|
#### links
|
||||||
|
|
||||||
##### How to add top-level links
|
If you wish to use Rails url helpers for link generation, e.g., `link(:resources) { resources_url }`, ensure your application sets
|
||||||
|
`Rails.application.routes.default_url_options`.
|
||||||
|
|
||||||
|
##### Top-level
|
||||||
|
|
||||||
JsonApi supports a [links object](http://jsonapi.org/format/#document-links) to be specified at top-level, that you can specify in the `render`:
|
JsonApi supports a [links object](http://jsonapi.org/format/#document-links) to be specified at top-level, that you can specify in the `render`:
|
||||||
|
|
||||||
@ -144,6 +147,33 @@ That's the result:
|
|||||||
|
|
||||||
This feature is specific to JsonApi, so you have to use the use the [JsonApi Adapter](adapters.md#jsonapi)
|
This feature is specific to JsonApi, so you have to use the use the [JsonApi Adapter](adapters.md#jsonapi)
|
||||||
|
|
||||||
|
|
||||||
|
##### Resource-level
|
||||||
|
|
||||||
|
In your serializer, define each link in one of the following methods:
|
||||||
|
|
||||||
|
As a static string
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
link :link_name, 'https://example.com/resource'
|
||||||
|
```
|
||||||
|
|
||||||
|
As a block to be evaluated. When using Rails, URL helpers are available.
|
||||||
|
Ensure your application sets `Rails.application.routes.default_url_options`.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
link :link_name_ do
|
||||||
|
"https://example.com/resource/#{object.id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
link(:link_name) { "https://example.com/resource/#{object.id}" }
|
||||||
|
|
||||||
|
link(:link_name) { resource_url(object) }
|
||||||
|
|
||||||
|
link(:link_name) { url_for(controller: 'controller_name', action: 'index', only_path: false) }
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
### serializer_opts
|
### serializer_opts
|
||||||
|
|
||||||
#### include
|
#### include
|
||||||
|
|||||||
@ -135,13 +135,15 @@ With the `:json_api` adapter, the previous serializers would be rendered as:
|
|||||||
|
|
||||||
#### ::link
|
#### ::link
|
||||||
|
|
||||||
e.g.
|
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
link :other, 'https://example.com/resource'
|
|
||||||
link :self do
|
link :self do
|
||||||
href "https://example.com/link_author/#{object.id}"
|
href "https://example.com/link_author/#{object.id}"
|
||||||
end
|
end
|
||||||
|
link :author { link_author_url(object) }
|
||||||
|
link :link_authors { link_authors_url }
|
||||||
|
link :other, 'https://example.com/resource'
|
||||||
|
link :posts { link_author_posts_url(object) }
|
||||||
|
```
|
||||||
```
|
```
|
||||||
|
|
||||||
#### #object
|
#### #object
|
||||||
|
|||||||
@ -20,9 +20,11 @@ module ActiveModel
|
|||||||
|
|
||||||
# Define a link on a serializer.
|
# Define a link on a serializer.
|
||||||
# @example
|
# @example
|
||||||
# link :self { "//example.com/posts/#{object.id}" }
|
# link(:self) { resource_url(object) }
|
||||||
# @example
|
# @example
|
||||||
# link :self, "//example.com/user"
|
# link(:self) { "http://example.com/resource/#{object.id}" }
|
||||||
|
# @example
|
||||||
|
# link :resource, "http://example.com/resource"
|
||||||
#
|
#
|
||||||
def link(name, value = nil, &block)
|
def link(name, value = nil, &block)
|
||||||
_links[name] = block || value
|
_links[name] = block || value
|
||||||
|
|||||||
@ -1,7 +1,12 @@
|
|||||||
|
require 'active_support/core_ext/module/delegation'
|
||||||
|
|
||||||
module ActiveModelSerializers
|
module ActiveModelSerializers
|
||||||
module Adapter
|
module Adapter
|
||||||
class JsonApi
|
class JsonApi
|
||||||
class Link
|
class Link
|
||||||
|
include SerializationContext.url_helpers
|
||||||
|
delegate :default_url_options, to: SerializationContext
|
||||||
|
|
||||||
def initialize(serializer, value)
|
def initialize(serializer, value)
|
||||||
@object = serializer.object
|
@object = serializer.object
|
||||||
@scope = serializer.scope
|
@scope = serializer.scope
|
||||||
|
|||||||
@ -15,6 +15,11 @@ module ActiveModelSerializers
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
initializer 'active_model_serializers.prepare_serialization_context' do
|
||||||
|
SerializationContext.url_helpers = Rails.application.routes.url_helpers
|
||||||
|
SerializationContext.default_url_options = Rails.application.routes.default_url_options
|
||||||
|
end
|
||||||
|
|
||||||
# This hook is run after the action_controller railtie has set the configuration
|
# This hook is run after the action_controller railtie has set the configuration
|
||||||
# based on the *environment* configuration and before any config/initializers are run
|
# based on the *environment* configuration and before any config/initializers are run
|
||||||
# and also before eager_loading (if enabled).
|
# and also before eager_loading (if enabled).
|
||||||
|
|||||||
@ -1,10 +1,24 @@
|
|||||||
module ActiveModelSerializers
|
module ActiveModelSerializers
|
||||||
class SerializationContext
|
class SerializationContext
|
||||||
|
class << self
|
||||||
|
attr_writer :url_helpers, :default_url_options
|
||||||
|
end
|
||||||
|
|
||||||
attr_reader :request_url, :query_parameters
|
attr_reader :request_url, :query_parameters
|
||||||
|
|
||||||
def initialize(request)
|
def initialize(request, options = {})
|
||||||
@request_url = request.original_url[/\A[^?]+/]
|
@request_url = request.original_url[/\A[^?]+/]
|
||||||
@query_parameters = request.query_parameters
|
@query_parameters = request.query_parameters
|
||||||
|
@url_helpers = options.delete(:url_helpers) || self.class.url_helpers
|
||||||
|
@default_url_options = options.delete(:default_url_options) || self.class.default_url_options
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.url_helpers
|
||||||
|
@url_helpers ||= Module.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.default_url_options
|
||||||
|
@default_url_options ||= {}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -18,6 +18,12 @@ class RailtieTest < ActiveSupport::TestCase
|
|||||||
"ActionController::Serialization should be included in ActionController::Base, but isn't"
|
"ActionController::Serialization should be included in ActionController::Base, but isn't"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test 'prepares url_helpers for SerializationContext' do
|
||||||
|
assert ActiveModelSerializers::SerializationContext.url_helpers.respond_to? :url_for
|
||||||
|
assert_equal Rails.application.routes.default_url_options,
|
||||||
|
ActiveModelSerializers::SerializationContext.default_url_options
|
||||||
|
end
|
||||||
|
|
||||||
test 'sets the ActiveModelSerializers.logger to Rails.logger' do
|
test 'sets the ActiveModelSerializers.logger to Rails.logger' do
|
||||||
refute_nil Rails.logger
|
refute_nil Rails.logger
|
||||||
refute_nil ActiveModelSerializers.logger
|
refute_nil ActiveModelSerializers.logger
|
||||||
|
|||||||
@ -1,18 +0,0 @@
|
|||||||
require 'test_helper'
|
|
||||||
|
|
||||||
class ActiveModelSerializers::SerializationContextTest < ActiveSupport::TestCase
|
|
||||||
def create_context
|
|
||||||
request = Minitest::Mock.new
|
|
||||||
request.expect(:original_url, 'original_url')
|
|
||||||
request.expect(:query_parameters, 'query_parameters')
|
|
||||||
|
|
||||||
ActiveModelSerializers::SerializationContext.new(request)
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_create_context_with_request_url_and_query_parameters
|
|
||||||
context = create_context
|
|
||||||
|
|
||||||
assert_equal context.request_url, 'original_url'
|
|
||||||
assert_equal context.query_parameters, 'query_parameters'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
# Execute this test in isolation
|
||||||
|
require 'support/isolated_unit'
|
||||||
|
require 'minitest/mock'
|
||||||
|
|
||||||
|
class SerializationContextTest < ActiveSupport::TestCase
|
||||||
|
include ActiveSupport::Testing::Isolation
|
||||||
|
|
||||||
|
def create_request
|
||||||
|
request = Minitest::Mock.new
|
||||||
|
request.expect(:original_url, 'original_url')
|
||||||
|
request.expect(:query_parameters, 'query_parameters')
|
||||||
|
end
|
||||||
|
|
||||||
|
class WithRails < SerializationContextTest
|
||||||
|
setup do
|
||||||
|
require 'rails'
|
||||||
|
require 'active_model_serializers'
|
||||||
|
make_basic_app
|
||||||
|
@context = ActiveModelSerializers::SerializationContext.new(create_request)
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'create context with request url and query parameters' do
|
||||||
|
assert_equal @context.request_url, 'original_url'
|
||||||
|
assert_equal @context.query_parameters, 'query_parameters'
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'url_helpers is set up for Rails url_helpers' do
|
||||||
|
assert_equal Module, ActiveModelSerializers::SerializationContext.url_helpers.class
|
||||||
|
assert ActiveModelSerializers::SerializationContext.url_helpers.respond_to? :url_for
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'default_url_options returns Rails.application.routes.default_url_options' do
|
||||||
|
assert_equal Rails.application.routes.default_url_options,
|
||||||
|
ActiveModelSerializers::SerializationContext.default_url_options
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class WithoutRails < SerializationContextTest
|
||||||
|
setup do
|
||||||
|
require 'active_model_serializers/serialization_context'
|
||||||
|
@context = ActiveModelSerializers::SerializationContext.new(create_request)
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'create context with request url and query parameters' do
|
||||||
|
assert_equal @context.request_url, 'original_url'
|
||||||
|
assert_equal @context.query_parameters, 'query_parameters'
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'url_helpers is a module when Rails is not present' do
|
||||||
|
assert_equal Module, ActiveModelSerializers::SerializationContext.url_helpers.class
|
||||||
|
refute ActiveModelSerializers::SerializationContext.url_helpers.respond_to? :url_for
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'default_url_options return a Hash' do
|
||||||
|
assert Hash, ActiveModelSerializers::SerializationContext.default_url_options.class
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -7,18 +7,24 @@ module ActiveModelSerializers
|
|||||||
LinkAuthor = Class.new(::Model)
|
LinkAuthor = Class.new(::Model)
|
||||||
class LinkAuthorSerializer < ActiveModel::Serializer
|
class LinkAuthorSerializer < ActiveModel::Serializer
|
||||||
link :self do
|
link :self do
|
||||||
href "//example.com/link_author/#{object.id}"
|
href "http://example.com/link_author/#{object.id}"
|
||||||
meta stuff: 'value'
|
meta stuff: 'value'
|
||||||
end
|
end
|
||||||
|
link(:author) { link_author_url(object.id) }
|
||||||
link :other, '//example.com/resource'
|
link(:link_authors) { url_for(controller: 'link_authors', action: 'index', only_path: false) }
|
||||||
|
link(:posts) { link_author_posts_url(object.id) }
|
||||||
|
link :resource, 'http://example.com/resource'
|
||||||
link :yet_another do
|
link :yet_another do
|
||||||
"//example.com/resource/#{object.id}"
|
"http://example.com/resource/#{object.id}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def setup
|
def setup
|
||||||
|
Rails.application.routes.draw do
|
||||||
|
resources :link_authors do
|
||||||
|
resources :posts
|
||||||
|
end
|
||||||
|
end
|
||||||
@post = Post.new(id: 1337, comments: [], author: nil)
|
@post = Post.new(id: 1337, comments: [], author: nil)
|
||||||
@author = LinkAuthor.new(id: 1337, posts: [@post])
|
@author = LinkAuthor.new(id: 1337, posts: [@post])
|
||||||
end
|
end
|
||||||
@ -29,7 +35,7 @@ module ActiveModelSerializers
|
|||||||
adapter: :json_api,
|
adapter: :json_api,
|
||||||
links: {
|
links: {
|
||||||
self: {
|
self: {
|
||||||
href: '//example.com/posts',
|
href: 'http://example.com/posts',
|
||||||
meta: {
|
meta: {
|
||||||
stuff: 'value'
|
stuff: 'value'
|
||||||
}
|
}
|
||||||
@ -37,7 +43,7 @@ module ActiveModelSerializers
|
|||||||
}).serializable_hash
|
}).serializable_hash
|
||||||
expected = {
|
expected = {
|
||||||
self: {
|
self: {
|
||||||
href: '//example.com/posts',
|
href: 'http://example.com/posts',
|
||||||
meta: {
|
meta: {
|
||||||
stuff: 'value'
|
stuff: 'value'
|
||||||
}
|
}
|
||||||
@ -68,13 +74,16 @@ module ActiveModelSerializers
|
|||||||
hash = serializable(@author, adapter: :json_api).serializable_hash
|
hash = serializable(@author, adapter: :json_api).serializable_hash
|
||||||
expected = {
|
expected = {
|
||||||
self: {
|
self: {
|
||||||
href: '//example.com/link_author/1337',
|
href: 'http://example.com/link_author/1337',
|
||||||
meta: {
|
meta: {
|
||||||
stuff: 'value'
|
stuff: 'value'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
other: '//example.com/resource',
|
author: 'http://example.com/link_authors/1337',
|
||||||
yet_another: '//example.com/resource/1337'
|
link_authors: 'http://example.com/link_authors',
|
||||||
|
resource: 'http://example.com/resource',
|
||||||
|
posts: 'http://example.com/link_authors/1337/posts',
|
||||||
|
yet_another: 'http://example.com/resource/1337'
|
||||||
}
|
}
|
||||||
assert_equal(expected, hash[:data][:links])
|
assert_equal(expected, hash[:data][:links])
|
||||||
end
|
end
|
||||||
|
|||||||
@ -63,6 +63,7 @@ module TestHelpers
|
|||||||
# Set a fake logger to avoid creating the log directory automatically
|
# Set a fake logger to avoid creating the log directory automatically
|
||||||
fake_logger = Logger.new(nil)
|
fake_logger = Logger.new(nil)
|
||||||
config.logger = fake_logger
|
config.logger = fake_logger
|
||||||
|
Rails.application.routes.default_url_options = { host: 'example.com' }
|
||||||
end
|
end
|
||||||
@app.respond_to?(:secrets) && @app.secrets.secret_key_base = '3b7cd727ee24e8444053437c36cc66c4'
|
@app.respond_to?(:secrets) && @app.secrets.secret_key_base = '3b7cd727ee24e8444053437c36cc66c4'
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,8 @@ class ActiveModelSerializers::RailsApplication < Rails::Application
|
|||||||
|
|
||||||
config.action_controller.perform_caching = true
|
config.action_controller.perform_caching = true
|
||||||
ActionController::Base.cache_store = :memory_store
|
ActionController::Base.cache_store = :memory_store
|
||||||
|
|
||||||
|
Rails.application.routes.default_url_options = { host: 'example.com' }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
ActiveModelSerializers::RailsApplication.initialize!
|
ActiveModelSerializers::RailsApplication.initialize!
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user