Skip to content

Commit 7c0c7ab

Browse files
authored
Merge pull request #1159 from butchmarshall/pluck_fix
Works around primary key being cast due to pluck bug
2 parents 78a2edd + 1ee9cc8 commit 7c0c7ab

4 files changed

Lines changed: 202 additions & 8 deletions

File tree

lib/jsonapi/active_relation_resource_finder.rb

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,19 +64,19 @@ def find_fragments(filters, options = {})
6464
records = find_records(filters, options)
6565

6666
table_name = _model_class.table_name
67-
pluck_fields = [concat_table_field(table_name, _primary_key)]
67+
pluck_fields = ["#{concat_table_field(table_name, _primary_key)} AS #{table_name}_#{_primary_key}"]
6868

6969
cache_field = attribute_to_model_field(:_cache_field) if options[:cache]
7070
if cache_field
71-
pluck_fields << concat_table_field(table_name, cache_field[:name])
71+
pluck_fields << "#{concat_table_field(table_name, cache_field[:name])} AS #{table_name}_#{cache_field[:name]}"
7272
end
7373

7474
model_fields = {}
7575
attributes = options[:attributes]
7676
attributes.try(:each) do |attribute|
7777
model_field = attribute_to_model_field(attribute)
7878
model_fields[attribute] = model_field
79-
pluck_fields << concat_table_field(table_name, model_field[:name])
79+
pluck_fields << "#{concat_table_field(table_name, model_field[:name])} AS #{table_name}_#{model_field[:name]}"
8080
end
8181

8282
fragments = {}
@@ -204,21 +204,21 @@ def find_related_monomorphic_fragments(source_rids, relationship, included_key,
204204
records = related_klass.apply_filters(records, filters, filter_options)
205205

206206
pluck_fields = [
207-
primary_key_field,
208-
concat_table_field(table_alias, related_klass._primary_key)
207+
"#{primary_key_field} AS #{_table_name}_#{_primary_key}",
208+
"#{concat_table_field(table_alias, related_klass._primary_key)} AS #{table_alias}_#{related_klass._primary_key}"
209209
]
210210

211211
cache_field = related_klass.attribute_to_model_field(:_cache_field) if options[:cache]
212212
if cache_field
213-
pluck_fields << concat_table_field(table_alias, cache_field[:name])
213+
pluck_fields << "#{concat_table_field(table_alias, cache_field[:name])} AS #{table_alias}_#{cache_field[:name]}"
214214
end
215215

216216
model_fields = {}
217217
attributes = options[:attributes]
218218
attributes.try(:each) do |attribute|
219219
model_field = related_klass.attribute_to_model_field(attribute)
220220
model_fields[attribute] = model_field
221-
pluck_fields << concat_table_field(table_alias, model_field[:name])
221+
pluck_fields << "#{concat_table_field(table_alias, model_field[:name])} AS #{table_alias}_#{model_field[:name]}"
222222
end
223223

224224
rows = records.pluck(*pluck_fields)
@@ -264,7 +264,11 @@ def find_related_polymorphic_fragments(source_rids, relationship, options = {})
264264
related_key = concat_table_field(_table_name, relationship.foreign_key)
265265
related_type = concat_table_field(_table_name, relationship.polymorphic_type)
266266

267-
pluck_fields = [primary_key, related_key, related_type]
267+
pluck_fields = [
268+
"#{primary_key} AS #{_table_name}_#{_primary_key}",
269+
"#{related_key} AS #{_table_name}_#{relationship.foreign_key}",
270+
"#{related_type} AS #{_table_name}_#{relationship.polymorphic_type}"
271+
]
268272

269273
relations = relationship.polymorphic_relations
270274

test/fixtures/active_record.rb

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,31 @@
88

99
### DATABASE
1010
ActiveRecord::Schema.define do
11+
create_table :sessions, id: false, force: true do |t|
12+
t.string :id, :limit => 36, :primary_key => true, null: false
13+
t.string :survey_id, :limit => 36, null: false
14+
15+
t.timestamps
16+
end
17+
18+
create_table :responses, force: true do |t|
19+
#t.string :id, :limit => 36, :primary_key => true, null: false
20+
21+
t.string :session_id, limit: 36, null: false
22+
23+
t.string :type
24+
t.string :question_id, limit: 36
25+
26+
t.timestamps
27+
end
28+
29+
create_table :response_texts, force: true do |t|
30+
t.text :text
31+
t.integer :response_id
32+
33+
t.timestamps
34+
end
35+
1136
create_table :people, force: true do |t|
1237
t.string :name
1338
t.string :email
@@ -360,6 +385,43 @@
360385
end
361386

362387
### MODELS
388+
class Session < ActiveRecord::Base
389+
self.primary_key = "id"
390+
has_many :responses
391+
end
392+
393+
class Response < ActiveRecord::Base
394+
belongs_to :session
395+
has_one :paragraph, :class_name => "ResponseText::Paragraph"
396+
397+
def response_type
398+
case self.type
399+
when "Response::SingleTextbox"
400+
"single_textbox"
401+
else
402+
"question"
403+
end
404+
end
405+
def response_type=type
406+
self.type = case type
407+
when "single_textbox"
408+
"Response::SingleTextbox"
409+
else
410+
"Response"
411+
end
412+
end
413+
end
414+
415+
class Response::SingleTextbox < Response
416+
has_one :paragraph, :class_name => "ResponseText::Paragraph", :foreign_key => :response_id
417+
end
418+
419+
class ResponseText < ActiveRecord::Base
420+
end
421+
422+
class ResponseText::Paragraph < ResponseText
423+
end
424+
363425
class Person < ActiveRecord::Base
364426
has_many :posts, foreign_key: 'author_id'
365427
has_many :comments, foreign_key: 'author_id'
@@ -736,6 +798,19 @@ class Robot < ActiveRecord::Base
736798
end
737799

738800
### CONTROLLERS
801+
class SessionsController < ActionController::Base
802+
include JSONAPI::ActsAsResourceController
803+
before_action :create_responses_relationships, :only => [:create,:update]
804+
805+
private
806+
def create_responses_relationships
807+
if !params[:data][:relationships].nil? && !params[:data][:relationships][:responses].nil?
808+
responses_params = params[:data][:relationships].delete(:responses)
809+
params[:data][:attributes][:responses] = responses_params
810+
end
811+
end
812+
end
813+
739814
class AuthorsController < JSONAPI::ResourceControllerMetal
740815
end
741816

@@ -1039,6 +1114,57 @@ class BaseResource < JSONAPI::Resource
10391114
abstract
10401115
end
10411116

1117+
class SessionResource < JSONAPI::Resource
1118+
key_type :uuid
1119+
1120+
attributes :survey_id, :responses
1121+
1122+
has_many :responses
1123+
1124+
def responses=params
1125+
params[:data].each { |datum|
1126+
response = @model.responses.build(((datum[:attributes].respond_to?(:permit))? datum[:attributes].permit(:response_type, :question_id) : datum[:attributes]))
1127+
1128+
(datum[:relationships] || {}).each_pair { |k,v|
1129+
case k
1130+
when "paragraph"
1131+
response.paragraph = ResponseText::Paragraph.create(((v[:data][:attributes].respond_to?(:permit))? v[:data][:attributes].permit(:text) : v[:data][:attributes]))
1132+
end
1133+
}
1134+
}
1135+
end
1136+
def responses
1137+
end
1138+
1139+
def self.creatable_fields(context)
1140+
super + [
1141+
:id,
1142+
]
1143+
end
1144+
1145+
def fetchable_fields
1146+
super - [:responses]
1147+
end
1148+
end
1149+
1150+
class ResponseResource < JSONAPI::Resource
1151+
model_hint model: Response::SingleTextbox, resource: :response
1152+
1153+
has_one :session
1154+
1155+
attributes :question_id, :response_type
1156+
1157+
has_one :paragraph
1158+
end
1159+
1160+
class ParagraphResource < JSONAPI::Resource
1161+
model_name 'ResponseText::Paragraph'
1162+
1163+
attributes :text
1164+
1165+
has_one :response
1166+
end
1167+
10421168
class PersonResource < BaseResource
10431169
attributes :name, :email
10441170
attribute :date_joined, format: :date_with_timezone

test/integration/requests/request_test.rb

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,69 @@ def test_large_get
2020
assert_cacheable_jsonapi_get '/api/v2/books?include=book_comments,book_comments.author'
2121
end
2222

23+
def test_post_sessions
24+
session_id = SecureRandom.uuid
25+
26+
post '/sessions', params: {
27+
data: {
28+
id: session_id,
29+
type: "sessions",
30+
attributes: {
31+
survey_id: SecureRandom.uuid,
32+
},
33+
relationships: {
34+
responses: {
35+
data: [
36+
{
37+
type: "responses",
38+
attributes: {
39+
response_type: "single_textbox",
40+
question_id: SecureRandom.uuid,
41+
},
42+
relationships: {
43+
paragraph: {
44+
data: {
45+
type: "responses",
46+
response_type: "paragraph",
47+
attributes: {
48+
text: "This is my single textbox response"
49+
}
50+
}
51+
}
52+
}
53+
},
54+
],
55+
},
56+
},
57+
}
58+
}.to_json,
59+
headers: {
60+
'CONTENT_TYPE' => JSONAPI::MEDIA_TYPE,
61+
'Accept' => JSONAPI::MEDIA_TYPE
62+
}
63+
assert_jsonapi_response 201
64+
json_body = JSON.parse(response.body)
65+
session_id = json_body["data"]["id"]
66+
67+
# Get what we just created
68+
get "/sessions/#{session_id}?include=responses"
69+
assert_jsonapi_response 200
70+
json_body = JSON.parse(response.body)
71+
72+
assert(json_body.is_a?(Object));
73+
assert(json_body["included"].is_a?(Array));
74+
assert_equal("single_textbox", json_body["included"][0]["attributes"]["response_type"]["single_textbox"]);
75+
76+
get "/sessions/#{session_id}?include=responses,responses.paragraph"
77+
assert_jsonapi_response 200
78+
json_body = JSON.parse(response.body)
79+
80+
assert_equal("single_textbox", json_body["included"][0]["attributes"]["response_type"]["single_textbox"]);
81+
82+
# Rails 4.2.x branch will not retrieve the responses.paragraph, 5.x branch will - this looks to be a deeper, but unrelated bug
83+
#assert_equal("paragraphs", json_body["included"][1]["type"]);
84+
end
85+
2386
def test_get_inflected_resource
2487
assert_cacheable_jsonapi_get '/api/v8/numeros_telefone'
2588
end

test/test_helper.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ class CatResource < JSONAPI::Resource
240240

241241
JSONAPI.configuration.route_format = :underscored_route
242242
TestApp.routes.draw do
243+
jsonapi_resources :sessions
243244
jsonapi_resources :people
244245
jsonapi_resources :special_people
245246
jsonapi_resources :comments

0 commit comments

Comments
 (0)