Skip to content

Commit

Permalink
Implement Create operation
Browse files Browse the repository at this point in the history
  • Loading branch information
aldesantis committed Dec 29, 2016
1 parent 525a15c commit 86f972c
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 32 deletions.
2 changes: 1 addition & 1 deletion .rspec
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
--format documentation
--format progress
--color
--require spec_helper
26 changes: 1 addition & 25 deletions doc/04-the-create-operation.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,28 +23,4 @@ module API
end
```

## Overriding defaults

You can override the default model class (computed from the operation's namespace) by overriding the
`#build_record` method:

```ruby
module API
module V1
module Post
module Operation
module Create < Pragma::Operation::Create
private

def build_record
::Post.new
end
end
end
end
end
end
```

To override the policy, contract and decorator you can call the usual `#policy`, `#contract` and
`#decorator`.
To override the defaults of this operation, have a look at the [source code](https://github.com/pragmarb/pragma/blob/master/lib/pragma/operation/index.rb).
1 change: 1 addition & 0 deletions lib/pragma.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
require 'pragma/operation/defaults'
require 'pragma/operation/index'
require 'pragma/operation/show'
require 'pragma/operation/create'
require 'pragma/operation/update'

# A pragmatic architecture for building JSON APIs.
Expand Down
33 changes: 33 additions & 0 deletions lib/pragma/operation/create.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# frozen_string_literal: true
module Pragma
module Operation
# Finds the requested record, authorizes it, updates it accordingly to the parameters and
# responds with the decorated record.
#
# @author Alessandro Desantis
class Create < Pragma::Operation::Base
include Pragma::Operation::Defaults

def call
record = build_record
contract = build_contract(record)

validate! contract
authorize! contract

contract.save

respond_with resource: decorate(record)
end

protected

# Builds the requested record.
#
# @return [Object]
def build_record
self.class.model_klass.new
end
end
end
end
108 changes: 108 additions & 0 deletions spec/pragma/operation/create_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# frozen_string_literal: true
RSpec.describe Pragma::Operation::Create do
subject(:context) do
operation_klass.call(
current_user: current_user,
params: params
)
end

let(:params) do
{
author_id: 1,
title: 'My Post'
}
end

let(:contract_klass) do
Class.new(Pragma::Contract::Base) do
property :author_id
property :title

validation do
required(:title).filled
end
end
end

let(:operation_klass) do
Class.new(described_class) do
def build_record
OpenStruct.new
end
end.tap do |klass|
klass.send(:contract, contract_klass)
allow(klass).to receive(:name).and_return('API::V1::Post::Operation::Create')
end
end

let(:current_user) { nil }

it 'creates the record' do
expect(context.resource.to_h).to eq(
title: 'My Post',
author_id: 1
)
end

context 'when invalid parameters are supplied' do
let(:params) do
{
author_id: 1,
title: ''
}
end

it 'responds with 422 Unprocessable Entity' do
expect(context.status).to eq(:unprocessable_entity)
end
end

context 'when a decorator is defined' do
let(:decorator_klass) do
Class.new(Pragma::Decorator::Base) do
property :title
end
end

before do
operation_klass.send(:decorator, decorator_klass)
end

it 'decorates the updated resource' do
expect(context.resource.to_hash).to eq(
'title' => 'My Post'
)
end
end

context 'when a policy is defined' do
let(:policy_klass) do
Class.new(Pragma::Policy::Base) do
def create?
resource.author_id == user.id
end
end
end

before do
operation_klass.send(:policy, policy_klass)
end

context 'when the user is authorized' do
let(:current_user) { OpenStruct.new(id: 1) }

it 'permits the creation' do
expect(context.resource.to_h).to eq(title: 'My Post', author_id: 1)
end
end

context 'when the user is not authorized' do
let(:current_user) { OpenStruct.new(id: 2) }

it 'does not permit the creation' do
expect(context.status).to eq(:forbidden)
end
end
end
end
2 changes: 1 addition & 1 deletion spec/pragma/operation/index_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true
RSpec.describe Pragma::Operation::Index do
let(:context) { operation_klass.call(input_context) }
subject(:context) { operation_klass.call(input_context) }

let(:operation_klass) do
Class.new(described_class) do
Expand Down
4 changes: 2 additions & 2 deletions spec/pragma/operation/show_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true
RSpec.describe Pragma::Operation::Show do
let(:context) do
subject(:context) do
operation_klass.call(
current_user: current_user,
params: { id: 1 }
Expand Down Expand Up @@ -68,7 +68,7 @@ def show?
end
end

context 'when the user is authorized' do
context 'when the user is not authorized' do
let(:current_user) { OpenStruct.new(id: 2) }

it 'does not permit the retrievla' do
Expand Down
26 changes: 23 additions & 3 deletions spec/pragma/operation/update_spec.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
# frozen_string_literal: true
RSpec.describe Pragma::Operation::Update do
let(:context) do
subject(:context) do
operation_klass.call(
current_user: current_user,
params: { id: 1, title: 'New Title' }
params: params
)
end

let(:params) do
{
id: 1,
title: 'New Title'
}
end

let(:contract_klass) do
Class.new(Pragma::Contract::Base) do
property :author_id
Expand Down Expand Up @@ -41,6 +48,19 @@ def find_record
)
end

context 'when invalid parameters are supplied' do
let(:params) do
{
author_id: 1,
title: ''
}
end

it 'responds with 422 Unprocessable Entity' do
expect(context.status).to eq(:unprocessable_entity)
end
end

context 'when a decorator is defined' do
let(:decorator_klass) do
Class.new(Pragma::Decorator::Base) do
Expand Down Expand Up @@ -80,7 +100,7 @@ def update?
end
end

context 'when the user is authorized' do
context 'when the user is not authorized' do
let(:current_user) { OpenStruct.new(id: 2) }

it 'does not permit the update' do
Expand Down

0 comments on commit 86f972c

Please sign in to comment.