A High-level Architecture For The Web

About Trailblazer

Trailblazer gives you a high-level architecture for web applications.

Logic that used to get violently pressed into MVC is restructured and decoupled from the Rails framework. New abstraction layers like operations, form objects, authorization policies, data twins and view models guide you towards a better architecture.

By applying encapsulation and good OOP, Trailblazer maximizes reusability of components, gives you a more intuitive structure for growing applications and adds conventions and best practices on top of Rails' primitive MVC stack.

A polymorphic architecture sitting between controller and persistence is designed to handle many different contexts and helps to minimize code to handle various user roles and edge cases.

Check out who's using Trailblazer in production →

Get Started:
Trailblazer In 20 Minutes (Actually Even Less)

Controller


  class CommentsController < ApplicationController
    def new
      form Comment::Update
    end

    def create
      run Comment::Update do |op|
        return redirect_to comments_path(op.model)
      end

      render :new
    end
      

Controllers in Trailblazer end up as lean HTTP endpoints: they instantly dispatch to an operation.

No business logic is allowed in controllers, only HTTP-related tasks like redirects.

Model


  class Comment < ActiveRecord::Base
    has_many   :users
    belongs_to :thing

    scope :recent, -> { limit(10) }
  end
      

Models only contain associations, scopes and finders. Solely persistence logic is allowed.

That's right: No callbacks, no validations, no business logic in models.

Operation


  class Comment::Create < Trailblazer::Operation
    contract do
      property :body
      validates :body, length: {maximum: 160}
    end

    def process(params)
      if validate(params)

      else

      end
    end
  end
      

Per public action, there's one operation orchestrating the business logic.

This is where your domain code sits: Validation, callbacks, authorization and application code go here.

Operations are the only place to write to persistence via models.

Learn more

Form


  contract do
    property :body
    validates :body, length: {maximum: 160}

    property :author do
      property :email
      validates :email, email: true
    end
  end
      

Every operation contains a form object.

This is the place for validations.

Forms are plain Reform classes and allow all features you know from the popular form gem.

Forms can also be rendered using form builders like Formtastic or Simpleform.

Callback

Callbacks are invoked from the operation, where you want them to be triggered.

They can be configured in a separate Callback class.

Callbacks are completely decoupled and have to be invoked manually, they won't run magically.


  callback do
    on_create :notify_owner!

    property :author do
      on_add :reset_authorship!
    end
  end
      

Policy


    policy do
      user.admin? or not post.published?
    end
      

Policies allow authorization on a global or fine-granular level.

Again, this is a completely self-contained class without any coupling to the remaining tiers.

View Model


  class Comment::Cell < Cell::ViewModel
    property :body
    property :author

    def show
      render
    end

  private
    def author_link
      link_to "#{author.email}", author
    end
  end
      
        
  <div class="comment">
    <%= body %>
    By <%= author_link %>
  </div>
      

Cells encapsulate parts of your UI in separate view model classes and introduce a widget architecture.

Views are logic-less. There can be deciders and loops. Any method called in the view is directly called on the cell instance.

Rails helpers can still be used but are limited to the cell's scope.

Views


  <h1>Comments for <%= @thing.name %></h1>

  This was created <%= @thing.created_at %>

    <%= concept("comment/cell",
    collection: @thing.comments) %>
      

Controller views are still ok to use.

However, replacing huge chunks with cells is encouraged and will simplify your views.

Representer

Document APIs like JSON or XML are implemented with Representers which parse and render documents.

Representers are plain Roar classes. They can be automatically infered from the contract schema.

You can use media formats, hypermedia and all other Roar features.


  representer do
    include Roar::JSON::HAL

    property :body
    property :user, embedded: true

    link(:self) { comment_path(model) }
  end
    

Inheritance


  class Comment::Update < Create
    policy do
      is_owner?(model)
    end
  end
    

Trailblazer reintroduces object-orientation.

For each public action, there's one operation class.

Operations inherit contract, policies, representers, etc. and can be fine-tuned for their use case.

Polymorphism

Operations, forms, policies, callbacks are all designed for a polymorphic environment.

Different roles, contexts or rules are handled with subclasses instead of messy ifs.


  class Comment::Create < Trailblazer::Operation
    build do |params|
      Admin if params[:current_user].admin?
    end

    class Admin < Create
      contract do
        remove_validations! :body
      end
    end
      

File Layout


    app
    ├── concepts
    │   ├── comment
    │   │   ├── operations.rb
    │   │   ├── cell.rb
    │   │   ├── policy.rb
    │   │   ├── views
    │   │   │   ├── show.haml
    │   │   │   ├── list.haml
    │   │   │   ├── comment.css.sass
    │   │   └── twin.rb
    │   │
    │   └── post
    │       └── operations.rb
        

      

In Trailblazer, files are no longer organized by technology. Classes, views, assets, policies, and more, are all grouped by concept and sit in one directory.

A concept may embrace a simple CRUD concern, or an invoice PDF generator, and can be virtually anything.

Concepts in turn can be nested again, and provide you a more intuitive and easier to navigate file structure.

Gems

Trailblazer is an architectural style. However, what sounds nice in theory is backed by gems for you to implement that style.

The gems itself are completely self-contained, minimalistic and solve just one particular problem. They all have been in use in thousands of production sites for many years.

The Book

Yes, there's a book!

Written by the creator of Trailblazer, this book gives you 300 pages full of wisdom about Trailblazer and its gems, such as Reform, Cells and Roar.

The book comes with a sample app repository to conveniently browse through changes per chapter.

In the book, we build a realistic Rails application with Trailblazer that discusses convoluted requirements such as dynamic forms, polymorphic rendering and processing for signed-in users, file uploads, pagination, a JSON document API sitting on top of that, and many more problems you run into when building web applications.

Check out the full book description for a few more details about the content.

If you want to learn about this project and if you feel like supporting Open-Source, please buy and read it and let us know what you think.

Buy Book

Testimonials

"At some point of time we started to decouple our form objects from models. Things got a lot easier when we found out there is a ready to use solution which solves our exact problem. That was Reform. Soon after, we started using all other parts of Trailblazer and haven't regretted a second of our time we spent using it." Igor Pstyga, PeerStreet
"Here at Chefsclub, we are very happy with Trailblazer. Our application already has 32 concepts, 130+ operations, and Cells surprised us as an awesome feature. We feel pretty safe with it." Paulo Fabiano Langer, Chefsclub
"Trailblazer helps organize my code, the book showed me how. You can assume what each component does by its name, it's very easy and intuitive, it should be shipped as an essential part of Rails." Yuri Freire Lima, AzClick
Trailblazer has brought the fun back to Rails for me. It helps me organize large codebases into small, smart, testable chunks. Nick has brought together his years of insight in managing Rails projects and made them available for everyone. Any Rails engineer looking to expand past the default Rails Way should take a look at Trailblazer. Eric Skogen, Software Inventor
I haven't been this excited about Rails since 2007! Trailblazer - makes Rails development fun again. Especially on large projects. It's one of the better implementations of the ServiceObject / ViewModel / Form Object / Policy layers I've seen, which sooner or later ( rather sooner) you'll need. Nick Gorbikoff, Rinica Company