Liaison

How to Use Liaison

Add this to your Gemfile:

gem 'liaison'

Then run the bundler installer:

bundle

You instantiate Presenter classes in your controllers, setting them as instance variables so they can be passed to the views. The Presenter class takes the model name as a string (sign_up, for example) then a hash of options. Currently supported options are :fields, a list of attributes on the presenter ([:email, :password]); and :validator, a class that knows how to validate the data (SignUpValidator).

An instance of the Presenter object is Hash-like: it implements the Enumerable module, which means it has an #each method among many others; it also has a #[] method, which you can use to access values just like with the CGI params hash.

The business logic classes (SignUp in the below example) live under app/models and are tested as normal, except instead of requiring spec_helper they can likely require just rspec.

Validator classes (SignUpValidator in the below example) live under lib and must either descend from ActiveModel::Validator or implement the same interface (.kind, #kind, #validate that takes a record, and a constructor that takes a hash of options). They are also unit tested like normal and can likely get away with just requiring rspec instead of spec_helper. Sadly, in order to hook into the ActiveModel::Validations framework, you must pass the validator class itself instead of an object (SignUpValidator vs SignUpValidator.new).

Tutorial and Thought Process

A major idea of the presenter pattern is to break off the business logic from the view object, letting the view logic be a dumb instance that knows how to get, set, and validate values. The business logic can then query the presenter object for the values as needed.

It's just a class, which you can unit test as you please. A presenter object is passed in, then we pull the values out, make sure it's valid, and add errors to it as needed. This class does not deal directly with validations, state, or any of the ActiveModel nonsense.

Now you need to know how to use a Presenter object, so this is what the controller looks like:

In our new action we simply set the @sign_up i-var to an instance of the Presenter. In create we use that Presenter instance, adding CGI params in. Then we pass that to the SignUp class defined above and it's all boring from there.

The presenter method in the above example produces a new Presenter instance. This instance has a model name (sign_up), fields the form will handle (email, password, and account_name), and a validator (SignUpValidator). The validator is any instance of ActiveModel::Validator, for example:

You, the author of the business logic class, are in charge of checking in on these validations and errors. For example, before saving any objects you should check Presenter#valid?. And after you've saved something to the database you should add any errors onto the presenter using Presenter#add_errors.

Testing

When writing your unit tests it'll be handy to have a mock presenter around, which is why we package a MockPresenter class for you to use. It gives you access to the #have_errors and #have_no_errors RSpec matchers.