Skip to content

Commit

Permalink
[v7] Use cases (Micro::Case)
Browse files Browse the repository at this point in the history
  • Loading branch information
serradura committed Dec 13, 2019
1 parent 556a52d commit 07cb885
Show file tree
Hide file tree
Showing 18 changed files with 235 additions and 135 deletions.
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.6.5'

gem 'u-case', '~> 2.2', require: 'u-case/with_validation'
gem 'type_validator', '~> 1.0'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 6.0.1'
# Use sqlite3 as the database for Active Record
Expand Down
9 changes: 7 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ GEM
i18n (1.7.0)
concurrent-ruby (~> 1.0)
ice_nine (0.11.2)
interactor (3.1.1)
json (2.2.0)
kwalify (0.7.2)
launchy (2.4.3)
Expand Down Expand Up @@ -201,8 +200,13 @@ GEM
thor (0.20.3)
thread_safe (0.3.6)
tty-which (0.4.1)
type_validator (1.0.0)
activemodel (>= 3.2)
tzinfo (1.2.5)
thread_safe (~> 0.1)
u-attributes (1.2.0)
u-case (2.2.0)
u-attributes (~> 1.1)
virtus (1.0.5)
axiom-types (~> 0.1)
coercible (~> 1.0)
Expand All @@ -219,7 +223,6 @@ PLATFORMS
DEPENDENCIES
bootsnap (>= 1.4.2)
byebug
interactor (~> 3.1)
listen (>= 3.0.5, < 3.2)
puma (~> 4.1)
rails (~> 6.0.1)
Expand All @@ -228,7 +231,9 @@ DEPENDENCIES
spring
spring-watcher-listen (~> 2.0.0)
sqlite3 (~> 1.4)
type_validator (~> 1.0)
tzinfo-data
u-case (~> 2.2)

RUBY VERSION
ruby 2.6.5p114
Expand Down
74 changes: 30 additions & 44 deletions app/controllers/todos_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,64 +2,50 @@ class TodosController < ApplicationController
before_action :authenticate_user

def index
todos = todo_list.fetch_items_by_status(params[:status])

render_json(200, todos: Todo::Serialization.map_as_json(todos))
Todo::List::FetchItems
.call(user: current_user, params: params)
.on_success { |result| render_json(200, todos: result[:todos]) }
end

def create
todo_params = Todo::Params.to_save(params)

todo = todo_list.add_item(todo_params)

status = todo.persisted? ? 201 : 422

render_json(status, todo: Todo::Serialization.as_json(todo))
rescue ActionController::ParameterMissing => e
render_json(400, error: e.message)
Todo::List::AddItem
.call(user: current_user, params: params)
.on_failure(:parameter_missing) { |error| render_json(400, error: error[:message]) }
.on_failure(:invalid_todo) { |todo| render_json(422, todo: todo[:errors]) }
.on_success { |result| render_json(201, todo: result[:todo]) }
end

def destroy
todo = todo_list.delete_item(params[:id])

render_json(200, todo: Todo::Serialization.as_json(todo))
rescue ActiveRecord::RecordNotFound
render_json(404, todo: { id: 'not found' })
Todo::List::DeleteItem
.call(user: current_user, todo_id: params[:id])
.on_failure(:validation_error) { |result| render_json(400, errors: result[:errors]) }
.on_failure(:todo_not_found) { render_json(404, todo: { id: 'not found' }) }
.on_success { |result| render_json(200, todo: result[:todo]) }
end

def update
todo_params = Todo::Params.to_save(params)

todo = todo_list.update_item(params[:id], todo_params)

status = todo.valid? ? 200 : 422

render_json(status, todo: Todo::Serialization.as_json(todo))
rescue ActiveRecord::RecordNotFound
render_json(404, todo: { id: 'not found' })
rescue ActionController::ParameterMissing => e
render_json(400, error: e.message)
Todo::List::UpdateItem
.call(user: current_user, todo_id: params[:id], params: params)
.on_failure(:parameter_missing) { |error| render_json(400, error: error[:message]) }
.on_failure(:validation_error) { |result| render_json(400, errors: result[:errors]) }
.on_failure(:todo_not_found) { render_json(404, todo: { id: 'not found' }) }
.on_failure(:invalid_todo) { |todo| render_json(422, todo: todo[:errors]) }
.on_success { |result| render_json(200, todo: result[:todo]) }
end

def complete
todo = todo_list.complete_item(params[:id])

render_json(200, todo: Todo::Serialization.as_json(todo))
rescue ActiveRecord::RecordNotFound
render_json(404, todo: { id: 'not found' })
Todo::List::CompleteItem
.call(user: current_user, todo_id: params[:id])
.on_failure(:validation_error) { |result| render_json(400, errors: result[:errors]) }
.on_failure(:todo_not_found) { render_json(404, todo: { id: 'not found' }) }
.on_success { |result| render_json(200, todo: result[:todo]) }
end

def activate
todo = todo_list.activate_item(params[:id])

render_json(200, todo: Todo::Serialization.as_json(todo))
rescue ActiveRecord::RecordNotFound
render_json(404, todo: { id: 'not found' })
Todo::List::ActivateItem
.call(user: current_user, todo_id: params[:id])
.on_failure(:validation_error) { |result| render_json(400, errors: result[:errors]) }
.on_failure(:todo_not_found) { render_json(404, todo: { id: 'not found' }) }
.on_success { |result| render_json(200, todo: result[:todo]) }
end

private

def todo_list
@todo_list ||= Todo::List.of(current_user)
end
end
16 changes: 5 additions & 11 deletions app/controllers/users/registrations_controller.rb
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
class Users::RegistrationsController < ApplicationController
def create
user_params = User::Params.to_register(params)

user = User::Registration.new(user_params).create

if user.persisted?
render_json(201, user: user.as_json(only: [:id, :name, :token]))
else
render_json(422, user: user.errors.as_json)
end
rescue ActionController::ParameterMissing => e
render_json(400, error: e.message)
User::Register::Flow
.call(params: params)
.on_failure(:parameter_missing) { |error| render_json(400, error: error[:message]) }
.on_failure(:invalid_user_params) { |user| render_json(422, user: user[:errors]) }
.on_success { |result| render_json(201, user: result[:user]) }
end
end
52 changes: 0 additions & 52 deletions app/models/todo/list.rb

This file was deleted.

18 changes: 18 additions & 0 deletions app/models/todo/list/activate_item.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
class Todo::List::ActivateItem < Micro::Case
attributes :user, :todo_id

validates :user, type: User
validates :todo_id, numericality: { only_integer: true }

def call!
todo = user.todos.find_by(id: todo_id&.strip)

return Failure(:todo_not_found) unless todo

todo.completed_at = nil unless todo.active?

todo.save if todo.completed_at_changed?

Success { { todo: Todo::Serialization.as_json(todo) } }
end
end
20 changes: 20 additions & 0 deletions app/models/todo/list/add_item.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class Todo::List::AddItem < Micro::Case
attributes :user, :params

validates :user, type: User
validates :params, type: ActionController::Parameters

def call!
todo_params = Todo::Params.to_save(params)

todo = user.todos.create(todo_params)

todo_as_json = Todo::Serialization.as_json(todo)

return Success { { todo: todo_as_json } } if todo.persisted?

Failure(:invalid_todo) { { errors: todo_as_json } }
rescue ActionController::ParameterMissing => e
Failure(:parameter_missing) { { message: e.message } }
end
end
18 changes: 18 additions & 0 deletions app/models/todo/list/complete_item.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
class Todo::List::CompleteItem < Micro::Case
attributes :user, :todo_id

validates :user, type: User
validates :todo_id, numericality: { only_integer: true }

def call!
todo = user.todos.find_by(id: todo_id&.strip)

return Failure(:todo_not_found) unless todo

todo.completed_at = Time.current unless todo.completed?

todo.save if todo.completed_at_changed?

Success { { todo: Todo::Serialization.as_json(todo) } }
end
end
16 changes: 16 additions & 0 deletions app/models/todo/list/delete_item.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
class Todo::List::DeleteItem < Micro::Case
attributes :user, :todo_id

validates :user, type: User
validates :todo_id, numericality: { only_integer: true }

def call!
todo = user.todos.find_by(id: todo_id&.strip)

return Failure(:todo_not_found) unless todo

todo.destroy

Success { { todo: Todo::Serialization.as_json(todo) } }
end
end
12 changes: 12 additions & 0 deletions app/models/todo/list/fetch_items.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class Todo::List::FetchItems < Micro::Case
attributes :user, :params

validates :user, type: User
validates :params, type: ActionController::Parameters

def call!
todos = Todo.where_status(params[:status]).where(user_id: user.id)

Success { { todos: Todo::Serialization.map_as_json(todos) } }
end
end
25 changes: 25 additions & 0 deletions app/models/todo/list/update_item.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
class Todo::List::UpdateItem < Micro::Case
attributes :user, :todo_id, :params

validates :user, type: User
validates :params, type: ActionController::Parameters
validates :todo_id, numericality: { only_integer: true }

def call!
todo_params = Todo::Params.to_save(params)

todo = user.todos.find_by(id: todo_id&.strip)

return Failure(:todo_not_found) unless todo

todo.update(todo_params)

todo_as_json = Todo::Serialization.as_json(todo)

return Success { { todo: todo_as_json } } if todo.valid?

Failure(:invalid_todo) { { errors: todo_as_json } }
rescue ActionController::ParameterMissing => e
Failure(:parameter_missing) { { message: e.message } }
end
end
10 changes: 10 additions & 0 deletions app/models/user/register/flow.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class User
module Register
class Flow < Micro::Case
flow Step::NormalizeParams,
Step::ValidatePassword,
Step::CreateRecord,
Step::SerializeAsJson
end
end
end
17 changes: 17 additions & 0 deletions app/models/user/register/step/create_record.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
class User::Register::Step::CreateRecord < Micro::Case
attributes :name, :password, :password_confirmation

def call!
user = User.new(user_attributes).tap(&:save)

return Success { { user: user } } if user.persisted?

Failure(:invalid_user_params) { { errors: user.errors.as_json } }
end

private

def user_attributes
{ name: name, password_digest: password.digest, token: SecureRandom.uuid }
end
end
19 changes: 19 additions & 0 deletions app/models/user/register/step/normalize_params.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
class User::Register::Step::NormalizeParams < Micro::Case
attribute :params

validates! :params, type: ActionController::Parameters

def call!
user_params = User::Params.to_register(params)

Success do
{
name: user_params[:name].try(:squish),
password: User::Password.new(user_params[:password]),
password_confirmation: User::Password.new(user_params[:password_confirmation])
}
end
rescue ActionController::ParameterMissing => e
Failure(:parameter_missing) { { message: e.message } }
end
end
11 changes: 11 additions & 0 deletions app/models/user/register/step/serialize_as_json.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class User::Register::Step::SerializeAsJson < Micro::Case
attribute :user

validates! :user, type: User

def call!
Success do
{ user: user.as_json(only: [:id, :name, :token]) }
end
end
end
Loading

0 comments on commit 07cb885

Please sign in to comment.