Deadlift

Gem Version Code Climate Build Status

Deadlift is a powerful gem that you should be using if you want to remove fat from your controllers and models.

Installation

Add this line to your application's Gemfile:

gem 'deadlift'

And then execute:

$ bundle

Or install it yourself as:

$ gem install deadlift

Usage

TODO: Write usage instructions here

What is this?

The concept here is to be able to refactor this example logic:

# ProductsController.rb
..
def create
  @client = Product.new(product_params)
  if @product.save
    NotifyTechDepartment.new(@product.id).deliver
    NotifyCEOAboutProductIncreaseMailer.new(@product.id).deliver
    redirect_to @product
  else
    NotifyCEOAboutProductFailureMailer.new(@product.id).deliver
    render "new"
  end
end
..
private
  def product_params
    params.require[:product].permit(:name, :price, :brand, :category)
  end

to:

def create
  CreateProductDeadlift.new(params[:product])
    .add_trainer(self) # report to self a.k.a. the controller
    .add_trainer(NotifyCEOAboutProductIncrease.new)
    .perform
end

def create_success(performance)
  redirect_to performance.result
end

def create_failure(performance)
  @client = performance.barbell
  render "new"
end

Note how we are not asking if the save is successful. We are simply performing a deadlift and setting what will happen if the deadlift is successful and what will happen if it fails.

When a deadlift is performed a Performance object is passed to either create_success or create_failure depending on the deadlift's results. You can then access the barbell again from the performance or the result itself, which in this case is the created product.

Also, we do not need strong parameters since this will be taken care of in the Barbell stage

No pain, no gain!

Deadlifts

A deadlift is a fancy name for an Interactor which consists of all possible actions that should occur when performing it. Every deadlift needs a perform method. For instance, in the example above, when performing a deadlift (creating a product) I want to validate the passed in values, persist the product in the database and finally notify some tech-department that we have a new product in stock.

I'd define the deadlift like this:

# app/deadlifts/create_product_deadlift.rb
class CreateProductDeadlift < Deadlift::Base

  # Reference a barbell!
  def self.barbell(params)
    CreateProductBarbell.new(params)
  end

  def perform
    perform_and_report_for_valid do
      set_attributes
      persist
      notify_tech
    end
  end

private

  def set_attributes
    product.name = barbell.name
    product.price = barbell.price
    product.brand = barbell.brand
    product.category = barbell.category
  end

  def persist
    product.save
  end

  def notify_tech
    NotifyTechDepartment.new(product.id).deliver
  end

  def product
    @product ||= Product.new
  end

  # Setting what the result should be when calling performance.result
  def result
    product
  end
end

Barbells

A barbell is a fancy name for a plain reform contract. Obviously, to perform a deadlift you need a barbell. The barbell is a reform object initialized with params. If the barbell is present and valid then the Deadlift is performed.

# app/barbells/create_product_barbell.rb
class CreateProductBarbell < Deadlift::Barbell::Base
  model :product

  property :name
  property :price
  property :brand
  property :category

  validate :name, presence: true
  validate :price, presence: true
  validate :brand, presence: true
  validate :category, presence: true
end

Trainers

You can add a trainer to any deadlift. The deadlift reports to the trainer when it is done, whether it has succeeded or failed. A trainer is a PORO that can do anything after a deadlift is performed.

# app/trainers/notify_ceo_about_product_increase.rb
class NotifyCeoAboutProductIncrease

  def success(performance)
    @absence = performance.result
    NotifyCEOAboutProductIncreaseMailer.new(@absence.id).deliver
  end

  def failure(performance)
    attrs = performance.barbell.attributes
    NotifyCEOAboutProductFailureMailer.new(attrs: attrs).deliver
  end
end

Performances

A performance is an object passed from the deadlift results. You can ask the performance object for the #result. You can also ask for the barbell object or the deadlift if you somehow need it.

Development

After checking out the repo, run bundle install to install dependencies. Then, run bundle exec rspec to run the tests. You can also run bundle exec bin/console for an interactive prompt that will allow you to experiment.

To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/karlingen/deadlift. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

The gem is available as open source under the terms of the MIT License.