Skip to content
2 changes: 1 addition & 1 deletion lib/jsonapi/utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ module Utils

def self.included(base)
if base.respond_to?(:before_action)
base.before_action :setup_request, :check_request
base.before_action :jsonapi_request_handling
end
end
end
Expand Down
32 changes: 31 additions & 1 deletion lib/jsonapi/utils/request.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
module JSONAPI
module Utils
module Request
def jsonapi_request_handling
setup_request
check_request
end

def setup_request
@request ||=
JSONAPI::Request.new(
params,
params.dup,
context: context,
key_formatter: key_formatter,
server_error_callbacks: (self.class.server_error_callbacks || [])
Expand All @@ -14,6 +19,31 @@ def setup_request
def check_request
@request.errors.blank? || jsonapi_render_errors(json: @request)
end

def resource_params
build_params_for(:resource)
end

def relationship_params
build_params_for(:relationship)
end

private

def build_params_for(param_type)
return {} if @request.operations.empty?

keys = %i(attributes to_one to_many)
operation = @request.operations.find { |e| e.data.keys & keys == keys }

if operation.nil?
{}
elsif param_type == :relationship
operation.data.values_at(:to_one, :to_many).compact.reduce(&:merge)
else
operation.data[:attributes]
end
end
end
end
end
7 changes: 5 additions & 2 deletions spec/controllers/posts_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@

let(:post_params) do
{
data: { type: 'posts', attributes: attributes },
relationships: { author: author_params }
data: {
type: 'posts',
attributes: attributes,
relationships: { author: author_params }
}
}
end

Expand Down
10 changes: 10 additions & 0 deletions spec/controllers/users_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -282,21 +282,31 @@

describe '#update' do
let(:user) { User.first }
let(:post) { user.posts.first }

let(:update_params) do
user_params.tap do |params|
params[:data][:id] = user.id
params[:data][:attributes].merge!(first_name: 'Yukihiro')
params[:data][:relationships] = relationship_params
params.merge!(id: user.id)
end
end

let(:relationship_params) do
{ posts: { data: [{ id: post.id, type: "posts" }] } }
end

it 'update an existing user' do
patch :update, update_params

expect(response).to have_http_status :ok
expect(response).to have_primary_data('users')
expect(response).to have_data_attributes(fields)
expect(data['attributes']['first_name']).to eq(user_params[:data][:attributes][:first_name])

expect(user.reload.posts.count).to eq(1)
expect(user.posts.first).to eq(post)
end

context 'when resource was not found' do
Expand Down
18 changes: 7 additions & 11 deletions spec/support/controllers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def show_with_hash
options: { model: Post, resource: ::V2::PostResource }
end

# POST /users
# POST /posts
def create
post = Post.new(post_params)
if post.save
Expand All @@ -51,12 +51,7 @@ def create
private

def post_params
params.require(:data).require(:attributes).permit(:title, :body)
.merge(user_id: author_params[:id])
end

def author_params
params.require(:relationships).require(:author).require(:data).permit(:id)
resource_params.merge(user_id: relationship_params[:author])
end

def load_user
Expand All @@ -79,7 +74,7 @@ def show

# POST /users
def create
user = User.new(user_params)
user = User.new(resource_params)
if user.save
jsonapi_render json: user, status: :created
else
Expand All @@ -91,7 +86,7 @@ def create
# PATCH /users/:id
def update
user = User.find(params[:id])
if user.update(user_params)
if user.update(resource_params) && update_relationships(user)
jsonapi_render json: user
else
# Example of error rendering for exceptions or any object
Expand All @@ -102,7 +97,8 @@ def update

private

def user_params
params.require(:data).require(:attributes).permit(:first_name, :last_name, :admin)
def update_relationships(user)
return user if relationship_params[:posts].blank?
user.posts = Post.where(id: relationship_params[:posts])
end
end
2 changes: 1 addition & 1 deletion spec/support/models.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ class User < ActiveRecord::Base

class Post < ActiveRecord::Base
belongs_to :author, class_name: 'User', foreign_key: 'user_id'
validates :title, :body, presence: true
validates :title, :body, :author, presence: true
end
3 changes: 2 additions & 1 deletion spec/support/resources.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
class PostResource < JSONAPI::Resource
attributes :title, :body
has_one :author, class_name: 'User', foreign_key: 'user_id'
has_one :author
end

module V2
Expand All @@ -9,6 +9,7 @@ class PostResource < ::PostResource; end

class UserResource < JSONAPI::Resource
attributes :first_name, :last_name, :full_name

attribute :full_name

has_many :posts
Expand Down