Skip to content

Commit a290ca2

Browse files
author
Lee Richmond
committed
refactor specs
Separate out into different spec files, etc
1 parent 54692ac commit a290ca2

18 files changed

+659
-557
lines changed

gemfiles/rails_4.gemfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
source "http://artprod.dev.bloomberg.com/artifactory/api/gems/rubygems/"
44

55
gem "active_model_serializers", :git => "https://github.com/richmolj/active_model_serializers.git"
6-
gem "rails", "~> 4.0"
6+
gem "rails", "~> 4.1"
77

88
group :test do
99
gem "appraisal"

gemfiles/rails_4.gemfile.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ GIT
1111
PATH
1212
remote: ../
1313
specs:
14-
jsonapi_compliable (0.3.1)
14+
jsonapi_compliable (0.3.2)
1515
active_model_serializers (~> 0.10)
1616
jsonapi (~> 0.1.1.beta2)
1717
jsonapi_ams_extensions (~> 0.1)
@@ -208,7 +208,7 @@ DEPENDENCIES
208208
kaminari
209209
pry
210210
pry-byebug
211-
rails (~> 4.0)
211+
rails (~> 4.1)
212212
rake (~> 10.0)
213213
rspec-rails
214214
sqlite3

gemfiles/rails_5.gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ GIT
1111
PATH
1212
remote: ../
1313
specs:
14-
jsonapi_compliable (0.3.1)
14+
jsonapi_compliable (0.3.2)
1515
active_model_serializers (~> 0.10)
1616
jsonapi (~> 0.1.1.beta2)
1717
jsonapi_ams_extensions (~> 0.1)

lib/jsonapi_compliable/base.rb

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ module Base
88
included do
99
class_attribute :_jsonapi_compliable
1010
before_action :parse_fieldsets!
11+
after_action :reset_scope_flag
1112
end
1213

1314
def default_page_number
@@ -30,18 +31,22 @@ def jsonapi_scope(scope,
3031
scope = JSONAPICompliable::Scope::Sideload.new(self, scope).apply if includes
3132
scope = JSONAPICompliable::Scope::Sort.new(self, scope).apply if sort
3233
scope = JSONAPICompliable::Scope::Paginate.new(self, scope).apply if paginate
34+
@_jsonapi_scoped = true
3335
scope
3436
end
3537

38+
def reset_scope_flag
39+
@_jsonapi_scoped = false
40+
end
41+
3642
def parse_fieldsets!
3743
Util::FieldParams.parse!(params, :fields)
3844
Util::FieldParams.parse!(params, :extra_fields)
3945
end
4046

41-
# * Eager loads whitelisted includes
42-
# * Merges opts and ams_default_options
4347
def render_ams(scope, opts = {})
44-
scope = jsonapi_scope(scope) if scope.is_a?(ActiveRecord::Relation)
48+
opts[:scope] = true unless opts[:scope] == false
49+
scope = jsonapi_scope(scope) if !@_jsonapi_scoped && opts.delete(:scope)
4550
options = default_ams_options
4651
options[:include] = forced_includes || Util::IncludeParams.scrub(self)
4752
options[:json] = scope
@@ -60,6 +65,9 @@ def default_ams_options
6065
end
6166
end
6267

68+
# TODO: This nastiness likely goes away once jsonapi standardizes
69+
# a spec for nested relationships.
70+
# See: https://github.com/json-api/json-api/issues/1089
6371
def forced_includes(data = nil)
6472
return unless force_includes?
6573
data = raw_params[:data] unless data
@@ -85,9 +93,11 @@ def force_includes?
8593

8694
module ClassMethods
8795
def jsonapi(&blk)
88-
dsl = JsonapiCompliable::DSL.new
89-
dsl.instance_eval(&blk)
90-
self._jsonapi_compliable = dsl
96+
if !self._jsonapi_compliable
97+
dsl = JsonapiCompliable::DSL.new
98+
self._jsonapi_compliable = dsl
99+
end
100+
self._jsonapi_compliable.instance_eval(&blk)
91101
end
92102
end
93103
end

lib/jsonapi_compliable/scope/default_filter.rb

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,22 @@ class Scope::DefaultFilter < Scope::Base
44

55
def apply
66
dsl.default_filters.each_pair do |name, opts|
7-
next if find_filter(name)
7+
next if overridden?(name)
88
@scope = opts[:filter].call(@scope)
99
end
1010

1111
@scope
1212
end
13+
14+
private
15+
16+
def overridden?(name)
17+
if found = find_filter(name)
18+
found_aliases = found[name][:aliases]
19+
filter_param.keys.any? { |k| found_aliases.include?(k.to_sym) }
20+
else
21+
false
22+
end
23+
end
1324
end
1425
end

lib/jsonapi_compliable/scope/extra_fields.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
module JSONAPICompliable
22
class Scope::ExtraFields < Scope::Base
3-
43
def apply
54
each_extra_field do |extra_field|
65
@scope = extra_field[:proc].call(@scope)

lib/jsonapi_compliable/scope/filter.rb

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,5 @@ def each_filter
2828
yield filter, value
2929
end
3030
end
31-
32-
def filter_param
33-
params[:filter] || {}
34-
end
3531
end
3632
end

lib/jsonapi_compliable/scope/filterable.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,9 @@ def find_filter!(name)
1515
end
1616
{ filter_name => filter_value }
1717
end
18+
19+
def filter_param
20+
params[:filter] || {}
21+
end
1822
end
1923
end

spec/create_update_spec.rb

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
require 'spec_helper'
2+
3+
RSpec.describe 'create/update', type: :controller do
4+
controller(ApplicationController) do
5+
jsonapi { }
6+
7+
before_action :deserialize_jsonapi!, only: [:create, :update]
8+
9+
def create
10+
author = Author.new(author_params.except(:state_attributes))
11+
author.state = State.find_or_initialize_by(author_params[:state_attributes])
12+
author.save!(validate: false)
13+
render_ams(author, scope: false)
14+
end
15+
16+
def update
17+
author = Author.find(author_params[:id])
18+
author_params[:books_attributes].each do |attrs|
19+
book = Book.find_or_initialize_by(attrs)
20+
author.association(:books).add_to_target(book, :skip_callbacks)
21+
end
22+
author.association(:books).loaded!
23+
author.save!
24+
render_ams(author, scope: false)
25+
end
26+
27+
private
28+
29+
def author_params
30+
params.require(:author).permit!
31+
end
32+
end
33+
34+
let!(:virginia) { State.create!(name: 'virginia') }
35+
36+
context 'when creating' do
37+
it 'includes whatever nested relations were sent in the request in the response' do
38+
post :create, params: {
39+
data: {
40+
type: 'authors',
41+
attributes: { first_name: 'Stephen', last_name: 'King' },
42+
relationships: {
43+
state: {
44+
data: {
45+
type: 'states',
46+
id: virginia.id
47+
}
48+
},
49+
books: {
50+
data: [
51+
{ type: 'books', attributes: { title: 'The Shining' } }
52+
]
53+
}
54+
}
55+
}
56+
}
57+
58+
expect(json_included_types).to match_array(%w(states books))
59+
expect(json_include('states')['id']).to eq(virginia.id.to_s)
60+
end
61+
end
62+
63+
context 'when updating' do
64+
let!(:author) { Author.create!(first_name: 'Stephen', last_name: 'King', state: virginia) }
65+
let!(:old_book) { author.books.create(title: "The Shining") }
66+
67+
before do
68+
routes.draw { put "update" => "anonymous#update" }
69+
end
70+
71+
it 'should include relations sent as part of payload' do
72+
put :update, id: author.id, params: {
73+
data: {
74+
id: author.id,
75+
type: 'authors',
76+
relationships: {
77+
books: {
78+
data: [
79+
{
80+
type: 'books',
81+
attributes: {
82+
title: "The Firm"
83+
}
84+
}
85+
]
86+
}
87+
}
88+
}
89+
}
90+
91+
expect(json_included_types).to match_array(%w(books))
92+
expect(json_includes('books').length).to eq(1)
93+
expect(json_include('books')['id']).to eq(Book.last.id.to_s)
94+
author.reload
95+
expect(author.book_ids).to match_array(Book.pluck(:id))
96+
end
97+
end
98+
end

spec/deserialization_spec.rb

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
require 'spec_helper'
2+
3+
RSpec.describe 'deserialization', type: :controller do
4+
controller(ApplicationController) do
5+
jsonapi { }
6+
end
7+
8+
let(:payload) do
9+
{
10+
data: {
11+
type: 'authors',
12+
attributes: { first_name: 'Stephen', last_name: 'King' },
13+
relationships: {
14+
state: {
15+
data: {
16+
type: 'states',
17+
attributes: { name: 'virginia' },
18+
}
19+
},
20+
books: {
21+
data: [
22+
{ type: 'books', attributes: { title: 'The Shining' } }
23+
]
24+
}
25+
}
26+
}
27+
}
28+
end
29+
30+
31+
describe '#deserialize_jsonapi!' do
32+
before do
33+
controller.params = payload
34+
end
35+
36+
it 'preserves raw params as raw_params' do
37+
controller.deserialize_jsonapi!
38+
39+
if Rails::VERSION::MAJOR == 4
40+
expect(controller.raw_params).to eq(payload.deep_stringify_keys)
41+
else
42+
expect(controller.raw_params).to eq(payload)
43+
end
44+
end
45+
46+
it 'sets params to a rails-friendly payload' do
47+
controller.deserialize_jsonapi!
48+
expected = {
49+
author: {
50+
first_name: 'Stephen',
51+
last_name: 'King',
52+
state_attributes: {
53+
name: 'virginia'
54+
},
55+
books_attributes: [
56+
{ title: 'The Shining' }
57+
]
58+
}
59+
}
60+
expected.deep_stringify_keys! if Rails::VERSION::MAJOR == 4
61+
expect(controller.params).to eq(expected)
62+
end
63+
end
64+
end

0 commit comments

Comments
 (0)