mirror of
https://github.com/ditkrg/active_model_serializers.git
synced 2026-01-23 06:16:50 +00:00
commit
1aa64f2ac3
@ -3,6 +3,8 @@
|
||||
Breaking changes:
|
||||
|
||||
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.
|
||||
- Only implements `detail` and `source` as derived from `ActiveModel::Error`
|
||||
- Provides checklist of remaining questions and remaining parts of the spec.
|
||||
|
||||
30
Rakefile
30
Rakefile
@ -45,25 +45,23 @@ Rake::TestTask.new do |t|
|
||||
end
|
||||
|
||||
desc 'Run isolated tests'
|
||||
task isolated: ['test:isolated:railtie']
|
||||
task isolated: ['test:isolated']
|
||||
namespace :test do
|
||||
namespace :isolated do
|
||||
task :isolated do
|
||||
desc 'Run isolated tests for Railtie'
|
||||
task :railtie do
|
||||
require 'shellwords'
|
||||
dir = File.dirname(__FILE__)
|
||||
file = Shellwords.shellescape("#{dir}/test/active_model_serializers/railtie_test_isolated.rb")
|
||||
dir = Shellwords.shellescape(dir)
|
||||
|
||||
# https://github.com/rails/rails/blob/3d590add45/railties/lib/rails/generators/app_base.rb#L345-L363
|
||||
_bundle_command = Gem.bin_path('bundler', 'bundle')
|
||||
require 'bundler'
|
||||
Bundler.with_clean_env do
|
||||
command = "-w -I#{dir}/lib -I#{dir}/test #{file}"
|
||||
require 'shellwords'
|
||||
dir = File.dirname(__FILE__)
|
||||
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
|
||||
_bundle_command = Gem.bin_path('bundler', 'bundle')
|
||||
require 'bundler'
|
||||
Bundler.with_clean_env do
|
||||
isolated_test_files.all? do |test_file|
|
||||
command = "-w -I#{dir}/lib -I#{dir}/test #{Shellwords.shellescape(test_file)}"
|
||||
full_command = %("#{Gem.ruby}" #{command})
|
||||
system(full_command) or # rubocop:disable Style/AndOr
|
||||
fail 'Failures'
|
||||
end
|
||||
system(full_command)
|
||||
end or fail 'Failures' # rubocop:disable Style/AndOr
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -96,3 +96,12 @@ class PostsController < ApplicationController
|
||||
|
||||
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
|
||||
|
||||
##### 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`:
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
##### 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
|
||||
|
||||
#### include
|
||||
|
||||
@ -135,13 +135,15 @@ With the `:json_api` adapter, the previous serializers would be rendered as:
|
||||
|
||||
#### ::link
|
||||
|
||||
e.g.
|
||||
|
||||
```ruby
|
||||
link :other, 'https://example.com/resource'
|
||||
link :self do
|
||||
href "https://example.com/link_author/#{object.id}"
|
||||
href "https://example.com/link_author/#{object.id}"
|
||||
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
|
||||
|
||||
@ -20,9 +20,11 @@ module ActiveModel
|
||||
|
||||
# Define a link on a serializer.
|
||||
# @example
|
||||
# link :self { "//example.com/posts/#{object.id}" }
|
||||
# link(:self) { resource_url(object) }
|
||||
# @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)
|
||||
_links[name] = block || value
|
||||
|
||||
@ -1,7 +1,12 @@
|
||||
require 'active_support/core_ext/module/delegation'
|
||||
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class Link
|
||||
include SerializationContext.url_helpers
|
||||
delegate :default_url_options, to: SerializationContext
|
||||
|
||||
def initialize(serializer, value)
|
||||
@object = serializer.object
|
||||
@scope = serializer.scope
|
||||
|
||||
@ -15,6 +15,11 @@ module ActiveModelSerializers
|
||||
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
|
||||
# based on the *environment* configuration and before any config/initializers are run
|
||||
# and also before eager_loading (if enabled).
|
||||
|
||||
@ -1,10 +1,24 @@
|
||||
module ActiveModelSerializers
|
||||
class SerializationContext
|
||||
class << self
|
||||
attr_writer :url_helpers, :default_url_options
|
||||
end
|
||||
|
||||
attr_reader :request_url, :query_parameters
|
||||
|
||||
def initialize(request)
|
||||
def initialize(request, options = {})
|
||||
@request_url = request.original_url[/\A[^?]+/]
|
||||
@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
|
||||
|
||||
@ -18,6 +18,12 @@ class RailtieTest < ActiveSupport::TestCase
|
||||
"ActionController::Serialization should be included in ActionController::Base, but isn't"
|
||||
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
|
||||
refute_nil Rails.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)
|
||||
class LinkAuthorSerializer < ActiveModel::Serializer
|
||||
link :self do
|
||||
href "//example.com/link_author/#{object.id}"
|
||||
href "http://example.com/link_author/#{object.id}"
|
||||
meta stuff: 'value'
|
||||
end
|
||||
|
||||
link :other, '//example.com/resource'
|
||||
|
||||
link(:author) { link_author_url(object.id) }
|
||||
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
|
||||
"//example.com/resource/#{object.id}"
|
||||
"http://example.com/resource/#{object.id}"
|
||||
end
|
||||
end
|
||||
|
||||
def setup
|
||||
Rails.application.routes.draw do
|
||||
resources :link_authors do
|
||||
resources :posts
|
||||
end
|
||||
end
|
||||
@post = Post.new(id: 1337, comments: [], author: nil)
|
||||
@author = LinkAuthor.new(id: 1337, posts: [@post])
|
||||
end
|
||||
@ -29,7 +35,7 @@ module ActiveModelSerializers
|
||||
adapter: :json_api,
|
||||
links: {
|
||||
self: {
|
||||
href: '//example.com/posts',
|
||||
href: 'http://example.com/posts',
|
||||
meta: {
|
||||
stuff: 'value'
|
||||
}
|
||||
@ -37,7 +43,7 @@ module ActiveModelSerializers
|
||||
}).serializable_hash
|
||||
expected = {
|
||||
self: {
|
||||
href: '//example.com/posts',
|
||||
href: 'http://example.com/posts',
|
||||
meta: {
|
||||
stuff: 'value'
|
||||
}
|
||||
@ -68,13 +74,16 @@ module ActiveModelSerializers
|
||||
hash = serializable(@author, adapter: :json_api).serializable_hash
|
||||
expected = {
|
||||
self: {
|
||||
href: '//example.com/link_author/1337',
|
||||
href: 'http://example.com/link_author/1337',
|
||||
meta: {
|
||||
stuff: 'value'
|
||||
}
|
||||
},
|
||||
other: '//example.com/resource',
|
||||
yet_another: '//example.com/resource/1337'
|
||||
author: 'http://example.com/link_authors/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])
|
||||
end
|
||||
|
||||
@ -63,6 +63,7 @@ module TestHelpers
|
||||
# Set a fake logger to avoid creating the log directory automatically
|
||||
fake_logger = Logger.new(nil)
|
||||
config.logger = fake_logger
|
||||
Rails.application.routes.default_url_options = { host: 'example.com' }
|
||||
end
|
||||
@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
|
||||
ActionController::Base.cache_store = :memory_store
|
||||
|
||||
Rails.application.routes.default_url_options = { host: 'example.com' }
|
||||
end
|
||||
end
|
||||
ActiveModelSerializers::RailsApplication.initialize!
|
||||
|
||||
Loading…
Reference in New Issue
Block a user