LightOperations
When you want have slim controllers or some logic with several operations this gem could help you to have nice separated and clan code. CAN HELP YOU! :D
Installation
Add this line to your application's Gemfile:
gem 'light_operations'
And then execute:
$ bundle
Or install it yourself as:
$ gem install light_operations
Usage
Uses cases
Basic vote logic
Operation
class ArticleVoteBumperOperation < LightOperations::Core
rescue_from ActiveRecord::ActiveRecordError, with: :on_ar_error
def execute(_params = nil)
dependency(:article_model).tap do |article|
article.vote = article.vote.next
article.save
end
end
def on_ar_error(_exception)
fail!({ vote: 'could not be updated!' })
end
end
Controller
class ArticleVotesController < ApplicationController
def up
response = article_vote_bumper_op.run.success? ? { success: true } : article_vote_bumper_op.errors
render :up, json: response
end
private
def article_vote_bumper_op
@article_vote_bumper_op ||= ArticleVoteBumperOperation.new(article_model: article)
end
def article
Article.find(params.require(:id))
end
end
Basic recursion execution for collect newsfeeds from 2 sources
Operation
class CollectFeedsOperation < LightOperations::Core
rescue_from Timeout::Error, with: :on_timeout
def execute(params = {})
dependency(:http_client).get(params.fetch(:url)).body
end
def on_timeout
fail!
end
end
Controller
class NewsFeedsController < ApplicationController
DEFAULT_NEWS_URL = 'http://rss.best_news.pl'
BACKUP_NEWS_URL = 'http://rss.not_so_bad_news.pl'
def news
collect_feeds_op
on(success: :display_news, fail: :second_attempt)
.run(url: DEFAULT_NEWS_URL)
end
private
def second_attempt(_news, _errors)
collect_feeds_op
.on_fail(:display_old_news)
.run(url: BACKUP_NEWS_URL)
end
def display_news(news)
render :display_news, locals { news: news }
end
def display_old_news
end
def collect_feeds_op
@collect_feeds_op ||= CollectFeedsOperation.new(http_client: http_client)
end
def http_client
MyAwesomeHttpClient
end
end
Simple case when you want have user authorization
Operation
class AuthOperation < LightOperations::Core
rescue_from AuthFail, with: :on_auth_error
def execute(params = {})
dependency(:auth_service).login(login: login(params), password: password(params))
end
def on_auth_error(_exception)
fail!([login: 'unknown']) # or subject.errors.add(login: 'unknown')
end
def login(params)
params.fetch(:login)
end
def password(params)
params.fetch(:password)
end
end
Controller way #1
class AuthController < ApplicationController
def new
render :new, locals: { account: Account.new }
end
def create
auth_op
.bind_with(self)
.on_success(:create_session_with_dashbord_redirection)
.on_fail(:render_account_with_errors)
.run(params)
end
private
def create_session_with_dashbord_redirection(account)
session_create_for(account)
redirect_to :dashboard
end
def render_account_with_errors(account, _errors)
render :new, locals: { account: account }
end
def auth_op
@auth_op ||= AuthOperation.new(auth_service: auth_service)
end
def auth_service
@auth_service ||= AuthService.new
end
end
Controller way #2
class AuthController < ApplicationController
def new
render :new, locals: { account: Account.new }
end
def create
auth_op
.on_success{ |account| create_session_with_dashbord_redirection(account) }
.on_fail { |account, _errors| render :new, locals: { account: account } }
.run(params)
end
private
def create_session_with_dashbord_redirection(account)
session_create_for(account)
redirect_to :dashboard
end
def auth_op
@auth_op ||= AuthOperation.new(auth_service: auth_service)
end
def auth_service
@auth_service ||= AuthService.new
end
end
Controller way #3
class AuthController < ApplicationController
def new
render :new, locals: { account: Account.new }
end
def create
auth_op.on_success(&go_to_dashboard).on_fail(&go_to_login).run(params)
end
private
def go_to_dashboard
-> (account) do
session_create_for(account)
redirect_to :dashboard
end
end
def go_to_login
-> (account, _errors) { render :new, locals: { account: account } }
end
def auth_op
@auth_op ||= AuthOperation.new(auth_service: auth_service)
end
def auth_service
@auth_service ||= AuthService.new
end
end
When operation status is most importent we can simply use #success?
or #fail?
on the executed operation
Errors are available by #errors
after operation is executed
Contributing
- Fork it ( https://github.com/[my-github-username]/swift_operations/fork )
- 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 a new Pull Request