ActionCase
Implementation of use-case driven design for ruby projects. Keep your business logic in the right place!
Supports: Ruby 1.9.3 +
Installation
Add this line to your application's Gemfile:
gem 'action_case'
And then execute:
$ bundle
Or install it yourself as:
$ gem install action_case
Usage
There are a variety of classes available to implement use-case driven design principles and patterns in your project.
Creating use-case class
# /app/use_cases/survey_exporter.rb
require "csv"
module UseCases
module Surveys
class SurveyExporter < ActionCase::Base
def export_csv survey_id
begin
survey = resource.find(survey_id)
return respond CSV.generate({}) { |csv|
csv << [:id, :title, :created_at]
survey.entries.each do |entry|
csv << [entry.id, entry.title, entry.created_at]
end
}
rescue Exception => exception
log :error, exception.message
end
respond "Unable to export the survey due to errors", false
end
def resource
Survey
end
end
end
end
Items of note:
- Injection of concrete implementation via 'resource'
- Use of #resource in #export_csv method, not concrete implementation
- Use of inherited respond method to handle both successful and error responses
- While it isn't required, it is recommended to namespace your use-cases with a matching folder structure.
Leveraging Use-case (perhaps in a Rails controller)
Generic Handler Syntax
In many cases, you'll only have one operation in a given use case. When that is the case, you can cut down on verbosity by using the generic handler syntax.
Format: [use_case_class_name_snake_cased]_[success_or_error]
# /app/controllers/surveys_controller.rb
class SurveyController < ActionController::Base
# POST /surveys/:id/export
def export
UseCases::Surveys::SurveyExporter.new(self).export_csv params[:id]
end
def survey_exporter_success csv_output
flash[:notice] = "Survey successfully exported!"
send_data csv_output, type: "text/plain", filename: "survey-export.csv", disposition: "attachment"
end
def survey_exporter_error error_output
flash[:alert] = "There were issues exporting the survey - #{error_output}"
end
end
Items of note:
- We set the controller as the listener for the use-case, via 'self'
- SurveyController#export stays short, sweet and to the point.
- We avoid coupling by using a very event-like callback (tell don't ask) communication pattern.
Explicit Handler Syntax
As your application scales and business rules change, you may have related but slightly different method signatures on a given use-case with each requiring different responses. In those cases the more verbose explicit handler syntax is necessary.
Format: [class_name_snake_cased]_[method_name_snake_cased]_[success_or_error]
# /app/controllers/surveys_controller.rb
class SurveyController < ActionController::Base
# POST /surveys/:id/export
def export
UseCases::Surveys::SurveyExporter.new(self).export_csv params[:id]
end
def survey_exporter_export_csv_success csv_output
flash[:notice] = "Survey successfully exported!"
send_data csv_output, type: "text/plain", filename: "survey-export.csv", disposition: "attachment"
end
def survey_exporter_export_csv_error error_output
flash[:alert] = "There were issues exporting the survey - #{error_output}"
end
end
Items of note:
- The expanded method signatures including the
_export_csv
component
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request