Skip to content

Latest commit

 

History

History
142 lines (105 loc) · 4.26 KB

README.md

File metadata and controls

142 lines (105 loc) · 4.26 KB

Bullet Train Routes

Bullet Train Routes provides a vastly simplified method for defining shallow, nested resource routes in Rails applications when modules and namespaces are involved. We do this by introducing a model method to the Rails routing DSL, which serves as an interchangable substitute for the resources method.

Why?

As Rails applications grow and developers start reaching for tools like modules and namespaces to organize their domain model, it can be incredibly challenging to generate sensible routes and URLs using the traditional Rails routing DSL.

For example, if you've got a Project model and a Projects::Deliverable model nested under it, the following would be sensible URLs:

  • /projects/1 for a project show page.
  • /projects/1/deliverables for the deliverables index page.
  • /projects/deliverables/2 for a deliverable show page.

To produce these URLs with the standard Rails routing DSL, you'll end up with the following:

❌   Hard Example

collection_actions = [:index, :new, :create]

resources :projects do
  scope module: 'projects' do
    resources :deliverables, only: collection_actions
  end
end

namespace :projects do
  resources :deliverables, except: collection_actions
end

This is just one example, and not even the most complicated. Previously we published a comprehensive blog post to try and help developers with various examples like this, but there was no helping that the resulting code would be very difficult for the next developer to understand and maintain later.

In addition to all of this, trying to automatically generate these routes proved to be one of the most complicated and error-prone pieces of Super Scaffolding.

With Bullet Train Routes, the example above can be simplified like so:

✅   Easy Example

model "Project" do 
  model "Projects::Deliverable"
end

Other Examples

Here are additional before and after comparisons inspired by some of the examples in our original blog post.

Projects::Deliverable and Objective Nested Under It

If you're nesting a resource that isn't in the same namespace, you traditionally end up with a route definition that looks like this:

❌   Hard Example

namespace :projects do
  resources :deliverables
end

resources :projects_deliverables, path: 'projects/deliverables' do
  resources :objectives
end

This produces the following URLs:

  • /projects/deliverables/1 for a deliverable show view.
  • /projects/deliverables/1/objectives for the objectives index view.
  • /objectives/2 for an objective show view.

With Bullet Train Routes, you can simply define this as:

✅   Easy Example

model "Projects::Deliverable" do 
  model "Objective"
end

Orders::Fulfillment and Shipping::Package Nested Under It

If you're nesting a resource across namespaces, you'll end up with a route definition that looks like this:

❌   Hard Example

namespace :orders do
  resources :fulfillments
end

resources :orders_fulfillments, path: 'orders/fulfillments' do
  namespace :shipping do
    resources :packages
  end
end

This produces the following URLs:

  • /orders/fulfillments/1 for a fulfillment show view.
  • /orders/fulfillments/1/shipping/packages for the packages index view.
  • /shipping/packages/2 for a package show view.

With Bullet Train Routes, you can simply define this as:

✅   Easy Example

model "Orders::Fulfillment" do 
  model "Shipping::Package"
end

Interoperability

You can use the model method the same way you would the resources method, like so:

namespace :account do 
  model "Site", concerns: [:sortable] do 
    collection do 
      get :search
    end

    member do 
      post :publish
    end

    # Even this still works the way you'd expect.
    resources :pages
  end
end

Installation

Add this line to your application's Gemfile:

gem "bullet_train-routes"

And then execute:

$ bundle

License

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