Skip to content

Commit 5d5715a

Browse files
author
Lachlan Sylvester
committed
add support for links and data options for jsonapi adapter on has_many associations
1 parent 03ddeee commit 5d5715a

File tree

6 files changed

+70
-5
lines changed

6 files changed

+70
-5
lines changed

lib/action_controller/serialization.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ def get_serializer(resource, options = {})
2727
end
2828
ActiveModel::SerializableResource.serialize(resource, options) do |serializable_resource|
2929
if serializable_resource.serializer?
30+
serializable_resource.url_helper = self
3031
serializable_resource.serialization_scope ||= serialization_scope
3132
serializable_resource.serialization_scope_name = _serialization_scope
3233
begin

lib/active_model/serializable_resource.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ def serialization_scope=(scope)
3030
serializer_opts[:scope] = scope
3131
end
3232

33+
def url_helper=(url_helper)
34+
adapter_opts[:url_helper] = url_helper
35+
end
36+
3337
def serialization_scope
3438
serializer_opts[:scope]
3539
end

lib/active_model/serializer/adapter/json_api.rb

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@ class JsonApi < Adapter
77
def initialize(serializer, options = {})
88
super
99
@hash = { data: [] }
10-
10+
@url_helper = options[:url_helper]
1111
if fields = options.delete(:fields)
1212
@fieldset = ActiveModel::Serializer::Fieldset.new(fields, serializer.json_key)
1313
else
1414
@fieldset = options[:fieldset]
1515
end
1616
end
1717

18+
attr_reader :url_helper
19+
1820
def serializable_hash(options = nil)
1921
options = {}
2022
if serializer.respond_to?(:each)
@@ -41,10 +43,17 @@ def fragment_cache(cached_hash, non_cached_hash)
4143

4244
private
4345

44-
def add_relationships(resource, name, serializers)
46+
def add_relationships(resource, name, serializers, opts)
4547
resource[:relationships] ||= {}
46-
resource[:relationships][name] ||= { data: [] }
47-
resource[:relationships][name][:data] += serializers.map { |serializer| { type: serializer.type, id: serializer.id.to_s } }
48+
49+
if opts.fetch(:data, true)
50+
resource[:relationships][name] ||= { data: [] }
51+
resource[:relationships][name][:data] += serializers.map { |serializer| { type: serializer.type, id: serializer.id.to_s } }
52+
end
53+
if opts.fetch(:links, false)
54+
resource[:relationships][name] ||= {}
55+
resource[:relationships][name][:links] = { related: url_helper.url_for([serializer.object, name]) }
56+
end
4857
end
4958

5059
def add_relationship(resource, name, serializer, val=nil)
@@ -141,7 +150,7 @@ def add_resource_relationships(attrs, serializer, options = {})
141150
attrs[:relationships] ||= {}
142151

143152
if serializer.respond_to?(:each)
144-
add_relationships(attrs, key, serializer)
153+
add_relationships(attrs, key, serializer, opts)
145154
else
146155
if opts[:virtual_value]
147156
add_relationship(attrs, key, nil, opts[:virtual_value])
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
require 'test_helper'
2+
3+
module ActionController
4+
module Serialization
5+
class JsonApiHasManyUrlTest < ActionController::TestCase
6+
class MyController < ActionController::Base
7+
8+
def render_resource_with_url_association
9+
@tag = Tag.new(id: 1)
10+
@tag.posts = []
11+
render json: @tag, adapter: :json_api, serializer: LinkTagSerializer
12+
end
13+
end
14+
15+
tests MyController
16+
17+
def test_render_resource_with_url_association
18+
get :render_resource_with_url_association
19+
expected = {
20+
data: {
21+
id: "1",
22+
type: "tags",
23+
relationships: {
24+
posts: {
25+
links: {
26+
related: "http://test.host/tags/1/posts"
27+
}
28+
}
29+
}
30+
}
31+
}
32+
assert_equal expected.to_json, response.body
33+
end
34+
end
35+
end
36+
end

test/fixtures/poro.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
class Model
2+
extend ActiveModel::Naming
23
FILE_DIGEST = Digest::MD5.hexdigest(File.open(__FILE__).read)
34

45
def self.model_name
56
@_model_name ||= ActiveModel::Name.new(self)
67
end
78

9+
def to_model
10+
self
11+
end
12+
813
def initialize(hash={})
914
@attributes = hash
1015
end
@@ -33,6 +38,10 @@ def id
3338
@attributes[:id] || @attributes['id'] || object_id
3439
end
3540

41+
def to_param
42+
id.to_s
43+
end
44+
3645
def method_missing(meth, *args)
3746
if meth.to_s =~ /^(.*)=$/
3847
@attributes[$1.to_sym] = args[0]
@@ -80,6 +89,7 @@ def cache_key
8089
"#{self.class.name.downcase}/#{self.id}"
8190
end
8291
end
92+
Tag = Class.new(Model)
8393

8494
module Spam; end
8595
Spam::UnrelatedLink = Class.new(Model)
@@ -236,6 +246,10 @@ def self.root_name
236246
has_one :blog, key: :site
237247
end
238248

249+
LinkTagSerializer = Class.new(ActiveModel::Serializer) do
250+
has_many :posts, links: true, data: false
251+
end
252+
239253
VirtualValueSerializer = Class.new(ActiveModel::Serializer) do
240254
attributes :id
241255

test/test_helper.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ class Foo < Rails::Application
8686
module TestHelper
8787
Routes = ActionDispatch::Routing::RouteSet.new
8888
Routes.draw do
89+
get 'tags/:tag_id/posts', to: 'application#index', as: 'tag_posts'
8990
get ':controller(/:action(/:id))'
9091
get ':controller(/:action)'
9192
end

0 commit comments

Comments
 (0)