diff --git a/lib/jsonapi/active_relation_resource_finder.rb b/lib/jsonapi/active_relation_resource_finder.rb index af6595a01..b81624dcf 100644 --- a/lib/jsonapi/active_relation_resource_finder.rb +++ b/lib/jsonapi/active_relation_resource_finder.rb @@ -64,11 +64,11 @@ def find_fragments(filters, options = {}) records = find_records(filters, options) table_name = _model_class.table_name - pluck_fields = [concat_table_field(table_name, _primary_key)] + pluck_fields = ["#{concat_table_field(table_name, _primary_key)} AS #{table_name}_#{_primary_key}"] cache_field = attribute_to_model_field(:_cache_field) if options[:cache] if cache_field - pluck_fields << concat_table_field(table_name, cache_field[:name]) + pluck_fields << "#{concat_table_field(table_name, cache_field[:name])} AS #{table_name}_#{cache_field[:name]}" end model_fields = {} @@ -76,7 +76,7 @@ def find_fragments(filters, options = {}) attributes.try(:each) do |attribute| model_field = attribute_to_model_field(attribute) model_fields[attribute] = model_field - pluck_fields << concat_table_field(table_name, model_field[:name]) + pluck_fields << "#{concat_table_field(table_name, model_field[:name])} AS #{table_name}_#{model_field[:name]}" end fragments = {} @@ -203,13 +203,13 @@ def find_related_monomorphic_fragments(source_rids, relationship, options = {}) records = related_klass.apply_filters(records, filters, filter_options) pluck_fields = [ - primary_key_field, - concat_table_field(table_alias, related_klass._primary_key) + "#{primary_key_field} AS #{_table_name}_#{_primary_key}", + "#{concat_table_field(table_alias, related_klass._primary_key)} AS #{table_alias}_#{related_klass._primary_key}" ] cache_field = related_klass.attribute_to_model_field(:_cache_field) if options[:cache] if cache_field - pluck_fields << concat_table_field(table_alias, cache_field[:name]) + pluck_fields << "#{concat_table_field(table_alias, cache_field[:name])} AS #{table_alias}_#{cache_field[:name]}" end model_fields = {} @@ -217,7 +217,7 @@ def find_related_monomorphic_fragments(source_rids, relationship, options = {}) attributes.try(:each) do |attribute| model_field = related_klass.attribute_to_model_field(attribute) model_fields[attribute] = model_field - pluck_fields << concat_table_field(table_alias, model_field[:name]) + pluck_fields << "#{concat_table_field(table_alias, model_field[:name])} AS #{table_alias}_#{model_field[:name]}" end rows = records.pluck(*pluck_fields) @@ -263,7 +263,11 @@ def find_related_polymorphic_fragments(source_rids, relationship, options = {}) related_key = concat_table_field(_table_name, relationship.foreign_key) related_type = concat_table_field(_table_name, relationship.polymorphic_type) - pluck_fields = [primary_key, related_key, related_type] + pluck_fields = [ + "#{primary_key} AS #{_table_name}_#{_primary_key}", + "#{related_key} AS #{_table_name}_#{relationship.foreign_key}", + "#{related_type} AS #{_table_name}_#{relationship.polymorphic_type}" + ] relations = relationship.polymorphic_relations diff --git a/test/fixtures/active_record.rb b/test/fixtures/active_record.rb index b5e3dc40b..7ea3e774c 100644 --- a/test/fixtures/active_record.rb +++ b/test/fixtures/active_record.rb @@ -8,6 +8,31 @@ ### DATABASE ActiveRecord::Schema.define do + create_table :sessions, id: false, force: true do |t| + t.string :id, :limit => 36, :primary_key => true, null: false + t.string :survey_id, :limit => 36, null: false + + t.timestamps + end + + create_table :responses, force: true do |t| + #t.string :id, :limit => 36, :primary_key => true, null: false + + t.string :session_id, limit: 36, null: false + + t.string :type + t.string :question_id, limit: 36 + + t.timestamps + end + + create_table :response_texts, force: true do |t| + t.text :text + t.integer :response_id + + t.timestamps + end + create_table :people, force: true do |t| t.string :name t.string :email @@ -359,6 +384,43 @@ end ### MODELS +class Session < ActiveRecord::Base + self.primary_key = "id" + has_many :responses +end + +class Response < ActiveRecord::Base + belongs_to :session + has_one :paragraph, :class_name => "ResponseText::Paragraph" + + def response_type + case self.type + when "Response::SingleTextbox" + "single_textbox" + else + "question" + end + end + def response_type=type + self.type = case type + when "single_textbox" + "Response::SingleTextbox" + else + "Response" + end + end +end + +class Response::SingleTextbox < Response + has_one :paragraph, :class_name => "ResponseText::Paragraph", :foreign_key => :response_id +end + +class ResponseText < ActiveRecord::Base +end + +class ResponseText::Paragraph < ResponseText +end + class Person < ActiveRecord::Base has_many :posts, foreign_key: 'author_id' has_many :comments, foreign_key: 'author_id' @@ -735,6 +797,19 @@ class Robot < ActiveRecord::Base end ### CONTROLLERS +class SessionsController < ActionController::Base + include JSONAPI::ActsAsResourceController + before_action :create_responses_relationships, :only => [:create,:update] + + private + def create_responses_relationships + if !params[:data][:relationships].nil? && !params[:data][:relationships][:responses].nil? + responses_params = params[:data][:relationships].delete(:responses) + params[:data][:attributes][:responses] = responses_params + end + end +end + class AuthorsController < JSONAPI::ResourceControllerMetal end @@ -1038,6 +1113,57 @@ class BaseResource < JSONAPI::Resource abstract end +class SessionResource < JSONAPI::Resource + key_type :uuid + + attributes :survey_id, :responses + + has_many :responses + + def responses=params + params[:data].each { |datum| + response = @model.responses.build(((datum[:attributes].respond_to?(:permit))? datum[:attributes].permit(:response_type, :question_id) : datum[:attributes])) + + (datum[:relationships] || {}).each_pair { |k,v| + case k + when "paragraph" + response.paragraph = ResponseText::Paragraph.create(((v[:data][:attributes].respond_to?(:permit))? v[:data][:attributes].permit(:text) : v[:data][:attributes])) + end + } + } + end + def responses + end + + def self.creatable_fields(context) + super + [ + :id, + ] + end + + def fetchable_fields + super - [:responses] + end +end + +class ResponseResource < JSONAPI::Resource + model_hint model: Response::SingleTextbox, resource: :response + + has_one :session + + attributes :question_id, :response_type + + has_one :paragraph +end + +class ParagraphResource < JSONAPI::Resource + model_name 'ResponseText::Paragraph' + + attributes :text + + has_one :response +end + class PersonResource < BaseResource attributes :name, :email attribute :date_joined, format: :date_with_timezone diff --git a/test/integration/requests/request_test.rb b/test/integration/requests/request_test.rb index 4b0e4cc10..69a65abc2 100644 --- a/test/integration/requests/request_test.rb +++ b/test/integration/requests/request_test.rb @@ -20,6 +20,69 @@ def test_large_get assert_cacheable_jsonapi_get '/api/v2/books?include=book_comments,book_comments.author' end + def test_post_sessions + session_id = SecureRandom.uuid + + post '/sessions', params: { + data: { + id: session_id, + type: "sessions", + attributes: { + survey_id: SecureRandom.uuid, + }, + relationships: { + responses: { + data: [ + { + type: "responses", + attributes: { + response_type: "single_textbox", + question_id: SecureRandom.uuid, + }, + relationships: { + paragraph: { + data: { + type: "responses", + response_type: "paragraph", + attributes: { + text: "This is my single textbox response" + } + } + } + } + }, + ], + }, + }, + } + }.to_json, + headers: { + 'CONTENT_TYPE' => JSONAPI::MEDIA_TYPE, + 'Accept' => JSONAPI::MEDIA_TYPE + } + assert_jsonapi_response 201 + json_body = JSON.parse(response.body) + session_id = json_body["data"]["id"] + + # Get what we just created + get "/sessions/#{session_id}?include=responses" + assert_jsonapi_response 200 + json_body = JSON.parse(response.body) + + assert(json_body.is_a?(Object)); + assert(json_body["included"].is_a?(Array)); + assert_equal("single_textbox", json_body["included"][0]["attributes"]["response_type"]["single_textbox"]); + + get "/sessions/#{session_id}?include=responses,responses.paragraph" + assert_jsonapi_response 200 + json_body = JSON.parse(response.body) + + assert_equal("single_textbox", json_body["included"][0]["attributes"]["response_type"]["single_textbox"]); + + # Rails 4.2.x branch will not retrieve the responses.paragraph, 5.x branch will - this looks to be a deeper, but unrelated bug + #assert_equal("paragraphs", json_body["included"][1]["type"]); + end + def test_get_inflected_resource assert_cacheable_jsonapi_get '/api/v8/numeros_telefone' end diff --git a/test/test_helper.rb b/test/test_helper.rb index 249638f94..af286c605 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -240,6 +240,7 @@ class CatResource < JSONAPI::Resource JSONAPI.configuration.route_format = :underscored_route TestApp.routes.draw do + jsonapi_resources :sessions jsonapi_resources :people jsonapi_resources :special_people jsonapi_resources :comments