A new way to think about your Ruby applications.
Less::Interactions are a place to put all of your business logic. They’re intended to be used primarily inside a rails app but they don’t need rails to work.
Rails is great, but if you build a rails app of any size you start running into problems:
-
ActiveRecord’s before & after filters are the devil.
-
The code paths in my rails app are a fucking mess.
-
Where do I put this bit of code?
-
Having a model call another model just to call the previous model is stupid and error prone.
-
Where is the entry point to my app? Sometimes you access the app from places other than the controller (cron, console, background jobs), how do you know a safe entry point.
-
What are all the side effects of calling this method?
Less::Interactions are a place to put all of your business logic and still get all the rails goodness you love.
Before:
class ExpensesController < ApplicationController def create @expense = current_business.expenses.create params[:expense] respond_with @expense end end class Expense < ActiveRecord::Base # all sorts of before and after filters # doing things like updating bank account balances, budgets # creating other models like ExpenseItem or Transaction end
After:
# You don't need a context class, but we really like using one. class Context def initialize *args args[0].each do |name, value| instance_variable_set "@#{name}", value eval "def #{name}; instance_variable_get :@#{name}; end" end end end #Controller is basically the same class ExpensesController < ApplicationController def create @expense = Expenses::Save.run Context.new( business:current_business, user: current_user, params: params), some_other_thing_the_interaction_needs: "boo" respond_with @expense end end # found in /app/interactions/expenses.save.rb class Expenses::Save < Less::Interaction # A simple way of both enforcing params get passed in and creates and i_var and a getter for each expects # set an expectation for all the objects the context provides expects :some_other_thing_the_interaction_needs, allow_nil: true expects :business expects :user #only one of these is required expects_any :need_this, :or, :this # A way to document what you are expecting to be returned # Also creates setter and getter methods for each returns :user returns :was_this_successful # Method chain in use case is easy to see. # To have access to the getter and setter methods created with returns # you need the run method to return self def run do_somthing_with some_other_thing_the_interaction_needs build_or_find_an_expense setup_expense_items setup_transaction return @expense unless valid? save update_budgets update_bank_accounts @expense self end private # implementation of other methods # some of which call other interactions end
-
Check out the latest master to make sure the feature hasn’t been implemented or the bug hasn’t been fixed yet.
-
Check out the issue tracker to make sure someone already hasn’t requested it and/or contributed it.
-
Fork the project.
-
Start a feature/bugfix branch.
-
Commit and push until you are happy with your contribution.
-
Make sure to add tests for it. This is important so I don’t break it in a future version unintentionally.
-
Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
Copyright © 2015 LessEverything See LICENSE.txt for further details.