The Very Best Ruby on Rails Workflow – Ever!

Spread the word
Tweet about this on TwitterShare on Google+Share on FacebookPin on PinterestShare on RedditShare on TumblrEmail this to someonePrint this page

Ruby on Rails Workflow

I’ve been working with Ruby on Rails now for over 4 years, and I truly feel that I can say I’m pretty damn good at it. Not because I’m a genius, or an idiot savant when it comes to code. No, far from it. Rather because I’ve worked in RoR so much for those 4+ years. Not just applications that I started and built from scratch, but also applications others built before I knew what I was doing and I’ve since had to maintain, add to or debug.

I have made quite a few applications though, made the decisions on how to implement features and workflows and I have made some terrible mistakes. As we all have when it comes to programming. Not one of us can look at code we wrote more than a few years old and say, “This is exactly how I would have written it if I had started today.” It would be a lie, and anyone who has done any real amount of programming, that you tried to convince of this lie would shake their head at you.

In this post, I want to go over some of the basics as to how I start and build my Ruby on Rails applications. Most of my experience has been creating these at my day job and I feel I’ve made enough mistakes to really know what not to do. Below I’ve compiled a list of main gems, configurations and javascript plugins/libraries I use in almost every application. I’ll explain further on each one but if you’re a seasoned Rails developer and you really just want to see what another developer uses and get out, here you go:

  • My Gemfile
    • Haml
    • Devise
    • CanCan
    • Quite Assets
  • Application Configurations
    • application.rb
    • Always CoffeeScript
    • Sass vs Stylus
  • JavaScript Libraries and Plugins
    • backbone-rails
    • haml_coffee_assets
    • momentjs
    • $.cookie
    • notifIt
  • execJS Woes
  • node.js to Rescue
  • Passenger vs Puma

My Gemfile

My most commonly used gems in my applications are:

  • haml
  • devise
  • cancan
  • will_paginate
  • attr_encrypted
  • quiet_assets

Haml - HTML abstraction markup language

Haml (HTML abstraction markup language) is a HTML short-hand embraced by the Ruby community and has been a part of my Ruby on Rails workflow since the first time I tried it 4 years ago. The basics of Haml are the element you wish without the < and > and with a % prepended. divs with classes or ids can be simply declared by the css selector. Attributes for the elements are declared within curly braces and use the ruby hash syntax. Probably just easier to show you.

HTML
      <div id='this-div' class='my-div'>
        <h4>Hello World</h4>
        <img src="http://www.murderati.com/storage/25%20-%20Nothing-to-see-here-move-along.jpg?__SQUARESPACE_CACHEVERSION=1357039578942" alt="Nothing to see here" />
        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Porro neque suscipit laborum mollitia repellat, modi veritatis dolore commodi nulla dolores consectetur deserunt? Placeat iste minima ipsa rem, cupiditate nesciunt neque?</p>
      </div>
    

Haml
      #this-div.my-div
        %h4 Hello World
        %img{src: "http://www.murderati.com/storage/25%20-%20Nothing-to-see-here-move-along.jpg?__SQUARESPACE_CACHEVERSION=1357039578942", alt: "Nothing to see here"}
        %p Lorem ipsum dolor sit amet, consectetur adipisicing elit. Delectus possimus nemo, nulla quisquam dicta sint iure molestiae. Recusandae numquam doloribus eaque nihil quia officia, ipsum! Ipsam, fugiat aliquam odio officia!
    

Devise/CanCan

I have yet to create a Rails Application that didn’t use the CanCan gem. CanCan is a gem that helps manage user permissions based on roles they are assigned in your application.

Devise is a Rails engine used for login systems. It has built in controllers and views for creating and managing users for your application. It is built on top of warden gem and is pretty much a plug and play system with a world of different options and configurations to make sure it fits your needs.

I won’t go into how to use Devise because their documentation is outstanding, but here are a few pointers and some of my preferences when using it:

Customizing the Views

Devise has all the views you could possibly need for your login and/or registration system but what I’ve noticed is that I often need to alter them and even clean them up. This is easily accomplished generating the views into the project by running $ rails generate devise:views in your terminal. This will copy all of the views hidden within the gem into application’s app/views/ directory under devise/. After this I like to immediately convert them to Haml with the html2haml gem. From Devise’s wiki:

  gem install html2haml
  for file in app/views/devise/**/*.erb; do html2haml -e $file ${file%erb}haml && rm -f $file; done

Install the html2haml gem and then run a Bash command to loop through all the files within the app/views/devise/ directory with the extension of .erb and convert it to Haml. Note I added the -f to this which is not on their wiki, but this just makes sure you don’t have to confirm the deletion of every file replaced by Haml.

Using CanCan with Roles

Again we’re not here for a CanCan tutorial so I’ll just assume that you read over the documentation or have used it before. With that in mind let me explain how I tend to use CanCan in my projects. I start by making sure my User model has a column/attribute called role in the database. I name the Devise model User but you can obviously name it whatever you want. The role column should be an integer and we’ll populate it using constants that we setup in our model.

  class User < ActiveRecord::Base
    class Roles
      GUEST     =   0
      STANDARD  =  10
      ADMIN     =  50
      SUPER     = 100
      GOD_ROLE  = 999

      LABELS = { GUEST => "Guest", STANDARD => "Standard", ADMIN => "Administrator", SUPER => "Super Admin" }

      def self.options_for_select
        LABELS.sort.collect { |arr| arr.reverse }
      end
    end
  end

Now throughout our project we can use the constant User::Roles::ADMIN to declare a user’s role or test against when were deciding if they have permissions to complete an action. To make this even easier, I write methods to test for specific roles. Like so:

  class User < ActiveRecord::Base
    # ... omitted ...

    ###============###
    #     ROLES
    ###============###
    # Tests self.role vs Roles::GUEST
    #
    # ==== Returns:
    # Boolean
    def guest?
      role == Roles::GUEST
    end

    # Tests self.role vs Roles::STANDARD
    #
    # ==== Returns:
    # Boolean
    def standard?
      role == Roles::STANDARD
    end

    # continue with other roles within Roles class
  end

So now we can have the ability to include a button or refuse access to a page by simply calling current_user.standard?. Let’s see how this will work with CanCan’s ability.rb:

  class Ability 
    include CanCan::Ability
  
    def initialize(user)
      unless user.active?
        cannot :manage, Account
        cannot :manage, User
      else
        can :manage, user
        can :read, user.account
      end

      if user.standard?
        can :update, user
        can :update, Account, id: user.account_id
      end
  
      if user.admin?
        can :manage, Account, id: user.account_id
        can :manage, User, account_id: user.account_id
      end

      if user.god?
        can :manage, :all
      end
    end
  end

Running through this quickly. .active? is just testing a boolean attribute in the database and is an easy way to lockout anyone that has been disabled in your system. We are using our role methods to easily declare which uses can do what with the if user.<role>? blocks.

Notice the the user.god? and User::Roles::GOD_ROLE being used here, this is a very clever way to allow you and any co-workers to be able to move around the application in production and see and do anything. I never allow this role to created or any user to be promoted to this role within the actual application, but rather this has to be done manually in the database or via the rails console. When providing support for users, this becomes a whole hell of a lot easier when you can actually log into the system and see exactly what the users are seeing.

Etc… Etc…

Quickly so this post doesn’t get horribly long, we’ll briefly discuss the other useful gems.

will_paginate is a very simple gem that allows for pagination of lists in your application. It’s based on collections of models and is used most often in the index :action of your controllers. It can also be used to paginate has_many relationships in your views, such as will_paginate @account.users

attr_encrypted allows you to easily encrypt and decrypt attributes to on your models.

quiet_assets is a nice development gem that prevents Rails from printing out all the get requests for assets like stylesheets, javascripts and images. When you’re trying to debug errors or trying to figure out what data is being returned from your database queries you don’t need to see that all your icons on the page have been loaded.

Application Configurations

I already mentioned quite_assets gem earlier to keep the log manageable for debugging, but that’s just one good tip. Here are a few simple configurations that I use often:

  # config/application.rb

  config.assets.paths << Rails.root.join("lib", "assets", "javascripts")
  config.assets.paths << Rails.root.join("lib", "assets", "stylesheets")

  config.generators.stylesheets = false
  config.generators.javascripts = false

The first two lines here add lib/assets/javascripts/ and lib/assets/stylesheets/ paths to be accessible via the asset pipeline. vendor/assets/** is for any JavaScript or CSS that you are using from other developers or companies, where lib/assets/** is for libraries or common CSS files you have written and use in multiple projects.

The next configurations are to prevent Rails from generating supporting assets when running rails g controller <controller>. Why you ask? Mostly because I truly feel it’s a bad idea to have specific styles for each controller in your application. This can lead to very fragmented styles throughout your application and also a lot of repeated CSS. I really think it’s better to organize your CSS in a more sensical fashion, to see how please refer to my post on my PHP BoilerPlate.

The same could be said for JavaScript but this is less of a concern for me. Mostly I include this for JavaScript because I tend to use BackboneJS with my Rails applications and BackboneJS has it’s own file structure that I follow.

Always CoffeeScript

Speaking of assets, I do use the default CoffeeScript in Rails and recommend anyone nervous about diving in to CoffeeScript to just bite the bullet. If you’re comfortable with Ruby already, then you’re just about half way there to understanding CoffeeScript. I could go on, but I’ve already done this rant before.

Sass vs Stylus

Sass vs Stylus

For CSS, I was using Sass, again the default in Rails, and three months ago probably would never had looked twice at any other preprocessor language for CSS. Yet recently I was playing around with MeteorJS and decided to embrace Stylus and immediately loved the lack of curly braces, semicolons and even colons. Just out of curiosity, I looked to see if there was perhaps a gem for stylus and wouldn’t you know it? There was. If you’re new to ruby, here’s a hint… there is always a gem for it. Seriously, always Google it, because it’ll probably save you a lot of time and anguish.

JavaScript Libraries and Plugins

To make any web application, you’re going to be using JavaScript; it’s unavoidable and you should embrace it. This day and age, people are expecting more responsive applications on the web. The days of fill in a form, hit submit and wait to be redirected to another page are waning. Proof of this can be seen in the popularity of native android and iOS apps and the growing community of MeteorJS. These all give the user almost immediate response to their actions and very often update data in real time.

As I mentioned above, I use BackboneJS for a lot of my applications, this is not to say that it’s always a fit. Yet because BackboneJS is so light-weight and it’s easy to just use the pieces of it you want, unlike some JavaScript frameworks such as AngularJS, I usually throw in the gem and plan on using it until it becomes apparent that it’s not necessary.

Embrace the Framework

I have in the past made quite a few mistakes with BackboneJS and Rails and have come to a few realizations. Here are some of them:

Backbone is used to create and manage/update client rendered views, which means you don’t need to create the full views in Rails. There are probably a lot of developers that would scream at me for this, because of the idea of progressive enhancement and not having a server generated view makes this content unavailable to those who have JavaScript turned off. When it comes to websites, I completely agree with the idea of progressive enhancement. I do not, on the other hand, when it comes to web applications, especially if that application uses a login system.

When you’ve created an application paid or not that a user signs up for, there’s a level of responsibility put on the user. Those users made the decision that they would use your software to complete whatever task it is your application takes care of and in that decision they agree to some technological requirements, within reason that is. One of those is that it’s 2014 and the days of JavaScript is an evil doorway into hacking your computer are over. If you’re using the web these days you need JavaScript.

The first time I used BackboneJS with Rails I did not use either of the two gems that are out there. (backbone-on-rails and backbone-rails) Each had generators that created the MVC scaffolding like Rails does and at the time I was hesitant to have this framework on top of another framework. “So many files!” I proclaimed. So we simply used the Rails generated JavaScript files when creating a controller. The .js.coffee file generated for UsersController housed all the code for my User model, Users collection and all the many, many views related to this. As you can imagine this file became unbearably long and hard to manage.

Since this horrible experience, I’ve embraced backbone-rails gem. It creates a master class that all of your Models, Collections and Views are loaded into. It’s scaffolding breaks up all your models, collections, views and routers into their own files and makes organization a breeze. Coupled with haml_coffee_assets makes building out your templates easier and similar to your Rails views. (i.e. Haml)

Following this path turns a lot of your Rails application into more of an API rather than the whole application.

Moment.js

Moment.js is a wonderful library that turns dealing with dates and time in JavaScript less like having your fingernails pulled out and more like programming. It does a much better job of treating the JavaScript Date class like an object and really makes switching back and forth between Strings and instances of the Date classes a so much nicer. It also has nice .add() and .subtract() methods to easily add/subtract # days, months, years, etc to/from the date.

$.cookie

A nice library for managing browser cookies. Handles setting, deleting, altering and attributes such as path and expires. You may not always need this, but if you’re working heavily with cookies it will speed up your development quite a bit.

notifIt

notifIt is nice animated notification system for your application. I won’t go too much into it, because I actually wrote up a post on this earlier that you should take some time and look at.

execJS Woes

I’ve run into the same issue over and over again with this nasty gem and have lost hours of my life to it. The problem isn’t actually with the gem itself but rather one of its dependencies; libv8. All of this is actually a little beyond my comprehension because the libv8 gem is actually just go between, it allows ruby gems to talk to an actual os library called V8 and this horrible thing depends on the gcc library and apparently always wants the newest version of gcc. Anyone who also runs Centos for their production environment knows that you never have the most current version of gcc without quite a bit of work in the terminal, ssh’d into your server. It’s upsetting.

node.js to Rescue

I found the solution to this when I was trying to deploy a sinatra app/website, that uses the asset pipeline, to a new server. After hours of searching and a stackoverflow post that went unnoticed for a while I found the answer was node.js. From the execJS gitHub page:

ExecJS lets you run JavaScript code from Ruby. It automatically picks the best runtime available to evaluate your JavaScript program, then returns the result to you as a Ruby object.

Blah, blah, blah… install node.js on your server and forget about this horrible nightmare.

Passenger vs Puma

At my day job we have Phusion Passenger installed on all our servers and use it to run Rails apps in development, but trying to install a newer version of Passenger on a fresh Centos box with 512MB of RAM, I found out that Passenger didn’t really want to install without 1GB minimum of RAM. So I gave Puma a try.

From everything I have read about it, Puma’s supposed to faster than Passenger and it seems it. One thing I have noticed is that where Passenger kinda goes to sleep when no one is hitting the site, Puma is always ready. I know that you can configure Passenger to be always on as Puma seems to be, but it was a bit of a pain in the past when I did that. Also I think it takes away from Passenger’s strengths.

I’m rather new to Puma and my knowledge of Passenger is more on the I know how to use it side rather than know how or why it does what it does. If anyone has any insights, concerns or wants to make me feel foolish with their super server knowledge, I’d be happy to have a discussion about it. Hit me up on Twitter: @Sparkmasterflex

Wrapping It Up

I apologize that this post got super long, but it seems I had more to say than I expected. Again, this was not a tutorial on Ruby on Rails by any means and was meant more as a window into my RoR workflow. Also, message me on Twitter if you have any questions about any of this or want to share your configurations, favorite gems of to just argue with me about CoffeeScript vs JavaScript. I always love those discussions.

Spread the word
Tweet about this on TwitterShare on Google+Share on FacebookPin on PinterestShare on RedditShare on TumblrEmail this to someonePrint this page