cult3

Using Trailblazer Operations in Controllers and Views

May 25, 2016

Table of contents:

  1. Writing the tests
  2. Adding the routes
  3. Adding the Controllers
  4. Adding the Views
  5. Conclusion

Over the last couple of weeks we’ve looked at getting started with Trailblazer and Ruby on Rails, and Operations and Contracts.

A Trailblazer Operation encapsulates the given action of your application. So far in this little exploration of Trailblazer we’ve created an Operation for creating new Users.

Encapsulating an action in an Operation class is a really nice way of defining the logic for that action. As we saw in Getting started with Operations in Trailblazer, it’s also really easy to test the business logic of the Operation for the given action.

But how do we now use that Operation in the Controller and the View?

In today’s tutorial we will be connecting the dots to finish off the implementation for creating a new user using Trailblazer and Ruby on Rails.

Writing the tests

I’m definitely not a stickler for strict Test Driven Development. More often than not I tend to use the spike and stabalise method of writing code.

However sometimes I do find it beneficial to write out the tests first because it allows me to plan what I need to build. Just the act of writing each incremental test often allows me to get past the mental block of implementing something, even if it is relatively simple.

So with that being said, here are the controller tests that we will be looking to satisfy in today’s tutorial:

require 'test_helper'

class RegisterControllerTest < ActionController::TestCase
  test 'should display register form' do
    get :new

    assert_response :success
  end

  test 'should fail to register with invalid data' do
    post :create, user: { email: '', password: '' }

    assert_response 400
  end

  test 'should register new user' do
    post :create, user: { email: 'name@domain.com', password: 'password' }

    assert_response 302
    assert_redirected_to login_url
  end
end

In the first test I’m asserting that a GET request to the new method of the RegisterController returns a successful response. If this doesn’t return a successful response something has seriously went wrong.

Next I assert that passing invalid data to the create method will return a HTTP response code of 400.

And finally, I will assert that passing valid data to the create method will return a HTTP response code of 302 and we should be redirected to the login URL.

You will notice that I’m not testing every validation rule or circumstance or scenario in these tests. I prefer to test those kinds of things at the Unit level.

With the tests in place, we can now write the code to make them pass.

Adding the routes

The first thing I’m going to do is to add the routes that we require:

Rails
  .application
  .routes
  .draw do
    # Registration
    get 'register', to: 'register#new'
    post 'register', to: 'register#create'

    # Authentication
    get 'login', to: 'login#new'
  end

We’re not going to implement logging in into the application in today’s tutorial, but we need the login route to redirect to on a successful registration attempt.

If you are familiar with routing in Rails this should look fairly straight forward to you. If you are not familiar with routing in Rails, take a look at Defining URL routes in Ruby on Rails.

Adding the Controllers

Next up we can add the Controllers that we will need to make the tests pass.

First create a new file under the controllers directory called register_controller.rb:

class RegisterController < ApplicationController
end

If you remember back to my review of Trailblazer, a Controller in a Trailblazer application is simply a lean HTTP endpoint that does not contain any business logic.

So first up we can define the new method, which will display the registration form:

class RegisterController < ApplicationController
  def new
    form User::Create
  end
end

In this method we simply need to pass the Operation to the form method that was added to the Controller by Trailblazer.

Next we can implement the create method that will accept the POST request to create a new user:

class RegisterController < ApplicationController
  def new
    form User::Create
  end

  def create
    run User::Create do |op|
      return redirect_to login_url
    end

    render :new, status: 400
  end
end

Pretty nice huh? In this method we run the Operation and pass it a block. The block will only be executed if the request is run successfully. I absolutely love how simple Trailblazer makes my Controllers!

Inside the block I’m simply redirecting to the login page. But you could do whatever you want inside this block on a successful registration request.

If the Operation is not successful we can simply render the :new method and set a status of 400.

In this tutorial we’re simply using the login page as a destination for the redirect. So to make this work we will need a Controller and a View:

class LoginController < ApplicationController
  def new; end
end

I’ve just left the new method empty for now as we don’t actually have to implement anything in this Controller to make the tests pass.

Adding the Views

Now that we have the Controller methods implemented, we need to add the Views so Rails doesn’t complain.

First I will create a new directory under views called register and a new file called new.html.slim:

h1 Register - if @form.errors.any? ul - @form.errors.full_messages.each do |msg|
li = msg = form_for @form, url: register_url do |f| div = f.label :email =
f.text_field :email div = f.label :password = f.password_field :password div =
f.submit "Register"

This is just a simple form for the email and password and a submit button. If the form has any errors we can iterate through them and display them as a list.

We also need a view for the login route. Create a new directory under views called login and then create a new file called new.html.slim:

h1 Login

Again, we don’t actually need to implement a login form to make the tests pass, so this will be fine for now.

Now with everything in place, you should be able to run the tests and see them all pass! You can also boot up Rails in the browser and go through the registration flow yourself to verify that everything is working correctly.

Conclusion

So as you can see, Trailblazer really does make your Controllers lean HTTP endpoints!

I personally love this aspect of Trailblazer. I hate it when you open a project and the Controllers are totally stuffed with methods and all sorts of weird code to deal with business logic edge cases.

The more I use Trailblazer, the more I appreciate this style of architecture for medium to larger sized applications.

Philip Brown

@philipbrown

© Yellow Flag Ltd 2024.