/Rails3-Notes

New Project setup files like database.yml , .gitgnore and etc files example just copy and paste while creating new rails 3 project.

Primary LanguageShell

Rail3-Notes

New Project setup files like database.yml , .gitgnore and etc files example just copy and paste while creating new rails 3 project.

Rails .gitignore

A .gitignore file to accommodate Rails 3 projects.

More Information

Some files in a Rails project should not be checked into a Git version control repository. You can tell git to ignore certain files by creating a file called .gitignore in the top level of your working directory.

Rails 3 automatically creates a simple .gitignore file when a new application is generated. Here you'll find an example of a .gitignore file that designates additional files that may be part of a typical project.

Using the File

Copy the example file gitignore.example to the top level of your working directory and rename it .gitignore.

Note that git will not ignore a file that was already tracked before a rule was added to this file to ignore it. In such a case the file must be un-tracked, usually with git rm --cached filename.

Rails Best Practices

The goal of this guide is to present a set of best practices and style prescriptions for Ruby on Rails 3 development. Rails is an opinionated framework and this is an opinionated guide. In my mind I'm totally certain that Sass is superior to CSS and Haml (Slim) is superior to Erb.

Some of the advice here is applicable only to Rails 3.1+.

You can generate a PDF or an HTML copy of this guide using Transmuter.

Table of Contents

Developing Rails applications

Query Optimization

  • Active record query optimization in models
    • Use select with has_many and belongs_to on Active Record Associations

    • Using the select parameter in Active Record association, you can speed up your application about 50% and more. ```Ruby class Amenity < ActiveRecord::Base belongs_to :property, :select => 'id,name' end

      class Property < ActiveRecord::Base
          has_many :amenities, :select => 'id,name'
      end
      ```
      

Splitting Routes Into Smaller

  • Split route namespaces into different files

    config/routes.rb

    ActionController::Routing::Routes.draw do |map|
      map.resources :posts
      map.resources :comments
      map.logout '/logout', :controller => 'sessions', :action => 'destroy'
      map.login '/login', :controller => 'sessions', :action => 'create'
    end

    config/routes/developer.rb

    ActionController::Routing::Routes.draw do |map|
      map.namespace :developer do |dev|
        dev.resources :posts
        dev.resources :comments
        dev.logout '/logout', :controller => 'sessions', :action => 'destroy'
        dev.login '/login', :controller => 'sessions', :action => 'create'
      end
    end

    config/routes/admin.rb

    ActionController::Routing::Routes.draw do |map|
      map.namespace :admin do |admin|
        admin.resources :posts
        admin.resources :comments
        admin.logout '/logout', :controller => 'sessions', :action => 'destroy'
        admin.login '/login', :controller => 'sessions', :action => 'create'
      end
    end

    config/routes/api.rb

    ActionController::Routing::Routes.draw do |map|
      map.namespace :api do |api|
        api.resources :posts
        api.resources :comments
        api.logout '/logout', :controller => 'sessions', :action => 'destroy'
        api.login '/login', :controller => 'sessions', :action => 'create'
      end
    end
  • Then you should tell rails there are 3 additional route files.

  • You can set the configs in config/application.rb

    config.paths.config.routes.concat Dir[Rails.root.join("config/routes/*.rb")]
  • Advantage of performing this-:

    • It is easier to maintain
    • I only change the developer related routes in config/routes/developer.rb, without any possible to change the routes in admin or api namespace
    • Rails will only reload the developer routes if you only change the config/routes/developer.rb, instead of reloading the whole routes, which may be expensive when your routes are complicated.

Directly Access Object

  • Directly access an object if it’s present *If you want to access an object only if it’s present, you can use Rails’Object#presence/blank. *This is handy for any representation of objects where blank is the same as not present at all. For example, this simplifies a common check for HTTP POST/query parameters:

    state   = params[:state]   if params[:state].present?
    country = params[:country] if params[:country].present?
    region  = state || country || 'UK'

    …becomes:

    region = params[:state].presence || params[:country].presence || 'UK'
  • Put custom initialization code in config/initializers. The code in initializers executes on application startup.

  • The initialization code for each gem should be in a separate file with the same name as the gem, for example carrierwave.rb, active_admin.rb, etc.

  • Adjust accordingly the settings for development, test and production environment (in the corresponding files under config/environments/)

    • Mark additional assets for precompilation (if any):

      ```Ruby
      # config/environments/production.rb
      # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
      config.assets.precompile += %w( rails_admin/rails_admin.css rails_admin/rails_admin.js )
      ```
      

Grep an object’s available methods

  • Because Object.methods returns an array, you can grep that just like in this tip about grepping anything from your enumerables.
  • For example, if you are looking for a particular method of an object, you can easily narrow down the results like this:
    Object.methods.grep /inspect/
    O/P => ["inspect", "pretty_inspect", "pretty_print_inspect"]
    

Check Objects Relations Exist

  • How to check if objects or relations exist? Here’s an interesting fact when checking if objects or relations exist in a collection.
    • To check if there were any items present in a collection you can do something like this: Object.relation.present?

    • This, however, is better: Object.relation.any?

    • Turns out that - when you request associated objects for the first time - the any? method will perform a COUNT (*) SQL query where as the present? method will perform a SELECT (*) which is infinitely slower than performing a count. ``` property = Property.first property.amenities.present? # SQL (284.1ms) SELECT * FROM "amenities" WHERE ("amenity".property_id = 1)

      property = Property.first
      property.amenities.any?
      # SQL (1.2ms)   SELECT count(*) AS count_all FROM "amenities" WHERE ("amenities".property_id = 1)
      ```
      

The Beauty of Collect

  • To get an array of some property from the objects
    amount_array = account.orders.collect { |order| order.amount.some_operation }
  • For live project example
    property_list = Property.near(params[:place], 5)
    available_property_ids = property_list.collect(&:id)
  • we can also use map
    amount_array = account.orders.map { |order| order.amount.some_operation }

Optimize your code comments

  • FIXME, TODO and OPTIMIZE code comments
    • You can add some special notes to your source code comments in Rails to remind you later of stuff you need to do:
      class Property < ActiveRecord::Base
        # TODO add named_scopes
        # FIXME method A is broken
        # OPTIMIZE improve the code
      
        has_many :amenities
        ....
      end
    • You can list these special notes with a rake task:
      $ rake notes
      app/models/property.rb:
        * [2] [TODO] add named_scopes
        * [3] [FIXME] method A is broken
        * [4] [OPTIMIZE] improve the code
      

NoMethodError

  • How to get rid of from NoMethodError
    • First by using unless

      article = Article.find_by_title("My Article")
      unless article.nil?
        article.body
      end
    • Second by using new and trendy try

    • With try you can skip the nil? check and do the following:

    Article.find_by_title("My Article").try(:body) => #body or nil
    

Sql query on console

  • To see sql querry on console as active record log Just put below lines into development.rb file
    if "irb" == $0
      ActiveRecord::Base.logger = Logger.new(STDOUT)
    end

nil?,empty? and blank?

  • In Ruby, you check with nil? if an object is nil:
    article = nil
    article.nil?  # => true
    empty? checks if an element - like a string or an array f.e. - is empty:
    # Array
    [].empty?   #=> true
    # String
    "".empty?   #=> true
  • Rails adds the method blank? to the Object class:
    • An object is blank if it‘s false, empty, or a whitespace string. For example, “”, ” “, nil, [], and {} are blank. This simplifies
      if !address.nil? && !address.empty?
      
      to
      if !address.blank?
      

Configuration

  • Put custom initialization code in config/initializers. The code in initializers executes on application startup.

  • The initialization code for each gem should be in a separate file with the same name as the gem, for example carrierwave.rb, active_admin.rb, etc.

  • Adjust accordingly the settings for development, test and production environment (in the corresponding files under config/environments/)

    • Mark additional assets for precompilation (if any):

      ```Ruby
      # config/environments/production.rb
      # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
      config.assets.precompile += %w( rails_admin/rails_admin.css rails_admin/rails_admin.js )
      ```
      
  • Create an additional staging environment that closely resembles the production one.

Routing

  • When you need to add more actions to a RESTful resource (do you really need them at all?) use member and collection routes.

    # bad
    get 'subscriptions/:id/unsubscribe'
    resources :subscriptions
    
    # good
    resources :subscriptions do
      get 'unsubscribe', :on => :member
    end
    
    # bad
    get 'photos/search'
    resources :photos
    
    # good
    resources :photos do
      get 'search', :on => :collection
    end
  • If you need to define multiple member/collection routes use the alternative block syntax.

    resources :subscriptions do
      member do
        get 'unsubscribe'
        # more routes
      end
    end
    
    resources :photos do
      collection do
        get 'search'
        # more routes
      end
    end
  • Use nested routes to express better the relationship between ActiveRecord models.

    class Post < ActiveRecord::Base
      has_many :comments
    end
    
    class Comments < ActiveRecord::Base
      belongs_to :post
    end
    
    # routes.rb
    resources :posts do
      resources :comments
    end
  • Use namespaced routes to group related actions.

    namespace :admin do
      # Directs /admin/products/* to Admin::ProductsController
      # (app/controllers/admin/products_controller.rb)
      resources :products
    end
  • Never use the legacy wild controller route. This route will make all actions in every controller accessible via GET requests.

    # very bad
    match ':controller(/:action(/:id(.:format)))'

Controllers

  • Keep the controllers skinny - they should only retrieve data for the view layer and shouldn't contain any business logic (all the business logic should naturally reside in the model).
  • Each controller action should (ideally) invoke only one method other than an initial find or new.
  • Share no more than two instance variables between a controller and a view.

Models

  • Introduce non-ActiveRecord model classes freely.

  • Name the models with meaningful (but short) names without abbreviations.

  • If you need model objects that support ActiveRecord behavior like validation use the ActiveAttr gem.

    class Message
      include ActiveAttr::Model
    
      attribute :name
      attribute :email
      attribute :content
      attribute :priority
    
      attr_accessible :name, :email, :content
    
      validates_presence_of :name
      validates_format_of :email, :with => /^[-a-z0-9_+\.]+\@([-a-z0-9]+\.)+[a-z0-9]{2,4}$/i
      validates_length_of :content, :maximum => 500
    end

    For a more complete example refer to the RailsCast on the subject.

ActiveRecord

  • Avoid altering ActiveRecord defaults (table names, primary key, etc) unless you have a very good reason (like a database that's not under your control).

  • Group macro-style methods (has_many, validates, etc) in the beginning of the class definition.

  • Prefer has_many :through to has_and_belongs_to_many. Using has_many :through allows additional attributes and validations on the join model.

    # using has_and_belongs_to_many
    class User < ActiveRecord::Base
      has_and_belongs_to_many :groups
    end
    
    class Group < ActiveRecord::Base
      has_and_belongs_to_many :users
    end
    
    # prefered way - using has_many :through
    class User < ActiveRecord::Base
      has_many :memberships
      has_many :groups, through: :memberships
    end
    
    class Membership < ActiveRecord::Base
      belongs_to :user
      belongs_to :group
    end
    
    class Group < ActiveRecord::Base
      has_many :memberships
      has_many :users, through: :memberships
    end
  • Always use the new "sexy" validations.

  • When a custom validation is used more than once or the validation is some regular expression mapping, create a custom validator file.

    # bad
    class Person
      validates :email, format: { with: /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i }
    end
    
    # good
    class EmailValidator < ActiveModel::EachValidator
      def validate_each(record, attribute, value)
        record.errors[attribute] << (options[:message] || 'is not a valid email') unless value =~ /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
      end
    end
    
    class Person
      validates :email, email: true
    end
  • All custom validators should be moved to a shared gem.

  • Use named scopes freely.

    class User < ActiveRecord::Base
      scope :active, -> { where(active: true) }
      scope :inactive, -> { where(active: false) }
    
      scope :with_orders, -> { joins(:orders).select('distinct(users.id)') }
    end
  • Wrap named scopes in lambdas to initialize them lazily.

    # bad
    class User < ActiveRecord::Base
      scope :active, where(active: true)
      scope :inactive, where(active: false)
    
      scope :with_orders, joins(:orders).select('distinct(users.id)')
    end
    
    # good
    class User < ActiveRecord::Base
      scope :active, -> { where(active: true) }
      scope :inactive, -> { where(active: false) }
    
      scope :with_orders, -> { joins(:orders).select('distinct(users.id)') }
    end
  • When a named scope defined with a lambda and parameters becomes too complicated, it is preferable to make a class method instead which serves the same purpose of the named scope and returns an ActiveRecord::Relation object. Arguably you can define even simpler scopes like this.

    class User < ActiveRecord::Base
      def self.with_orders
        joins(:orders).select('distinct(users.id)')
      end
    end
  • Beware of the behavior of the update_attribute method. It doesn't run the model validations (unlike update_attributes) and could easily corrupt the model state.

  • Use user-friendly URLs. Show some descriptive attribute of the model in the URL rather than its id. There is more than one way to achieve this:

    • Override the to_param method of the model. This method is used by Rails for constructing a URL to the object. The default implementation returns the id of the record as a String. It could be overridden to include another human-readable attribute.

      ```Ruby
      class Person
        def to_param
          "#{id} #{name}".parameterize
        end
      end
      ```
      

      In order to convert this to a URL-friendly value, parameterize should be called on the string. The id of the object needs to be at the beginning so that it can be found by the find method of ActiveRecord.

    • Use the friendly_id gem. It allows creation of human-readable URLs by using some descriptive attribute of the model instead of its id.

      ```Ruby
      class Person
        extend FriendlyId
        friendly_id :name, use: :slugged
      end
      ```
      
      Check the [gem documentation](https://github.com/norman/friendly_id) for more information about its usage.
      

ActiveResource

  • When the response is in a format different from the existing ones (XML and JSON) or some additional parsing of these formats is necessary, create your own custom format and use it in the class. The custom format should implement the following four methods: extension, mime_type, encode and decode.

    module ActiveResource
      module Formats
        module Extend
          module CSVFormat
            extend self
    
            def extension
              'csv'
            end
    
            def mime_type
              'text/csv'
            end
    
            def encode(hash, options = nil)
              # Encode the data in the new format and return it
            end
    
            def decode(csv)
              # Decode the data from the new format and return it
            end
          end
        end
      end
    end
    
    class User < ActiveResource::Base
      self.format = ActiveResource::Formats::Extend::CSVFormat
    
      ...
    end
  • If the request should be sent without extension, override the element_path and collection_path methods of ActiveResource::Base and remove the extension part.

    class User < ActiveResource::Base
      ...
    
      def self.collection_path(prefix_options = {}, query_options = nil)
        prefix_options, query_options = split_options(prefix_options) if query_options.nil?
        "#{prefix(prefix_options)}#{collection_name}#{query_string(query_options)}"
      end
    
      def self.element_path(id, prefix_options = {}, query_options = nil)
        prefix_options, query_options = split_options(prefix_options) if query_options.nil?
        "#{prefix(prefix_options)}#{collection_name}/#{URI.parser.escape id.to_s}#{query_string(query_options)}"
      end
    end

    These methods can be overridden also if any other modifications of the URL are needed.

Migrations

  • Keep the schema.rb under version control.

  • Use rake db:schema:load instead of rake db:migrate to initialize an empty database.

  • Use rake db:test:prepare to update the schema of the test database.

  • Avoid setting defaults in the tables themselves (unless the db is shared between several applications). Use the model layer instead.

    def amount
      self[:amount] or 0
    end

    While the use of self[:attr_name] is considered fairly idiomatic, you might also consider using the slightly more verbose (and arguably more readable) read_attribute instead:

    def amount
      read_attribute(:amount) or 0
    end
  • When writing constructive migrations (adding tables or columns), use the new Rails 3.1 way of doing the migrations - use the change method instead of up and down methods.

    # the old way
    class AddNameToPerson < ActiveRecord::Migration
      def up
        add_column :persons, :name, :string
      end
    
      def down
        remove_column :person, :name
      end
    end
    
    # the new prefered way
    class AddNameToPerson < ActiveRecord::Migration
      def change
        add_column :persons, :name, :string
      end
    end

Views

  • Never call the model layer directly from a view.
  • Never make complex formatting in the views, export the formatting to a method in the view helper or the model.
  • Mitigate code duplication by using partial templates and layouts.
  • Add client side validation for the custom validators. The steps to do this are:
    • Declare a custom validator which extends ClientSideValidations::Middleware::Base

      ```Ruby
      module ClientSideValidations::Middleware
        class Email < Base
          def response
            if request.params[:email] =~ /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
              self.status = 200
            else
              self.status = 404
            end
            super
          end
        end
      end
      ```
      
    • Create a new file public/javascripts/rails.validations.custom.js.coffee and add a reference to it in your application.js.coffee file:

      ```
      # app/assets/javascripts/application.js.coffee
      #= require rails.validations.custom
      ```
      
    • Add your client-side validator:

      ```Ruby
      #public/javascripts/rails.validations.custom.js.coffee
      clientSideValidations.validators.remote['email'] = (element, options) ->
        if $.ajax({
          url: '/validators/email.json',
          data: { email: element.val() },
          async: false
        }).status == 404
          return options.message || 'invalid e-mail format'
      ```
      

Internationalization

  • No strings or other locale specific settings should be used in the views, models and controllers. These texts should be moved to the locale files in the config/locales directory.

  • When the labels of an ActiveRecord model need to be translated, use the activerecord scope:

    en:
      activerecord:
        models:
          user: Member
        attributes:
          user:
            name: "Full name"
    

    Then User.model_name.human will return "Member" and User.human_attribute_name("name") will return "Full name". These translations of the attributes will be used as labels in the views.

  • Separate the texts used in the views from translations of ActiveRecord attributes. Place the locale files for the models in a folder models and the texts used in the views in folder views.

    • When organization of the locale files is done with additional directories, these directories must be described in the application.rb file in order to be loaded.

      ```Ruby
      # config/application.rb
      config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')]
      ```
      
  • Place the shared localization options, such as date or currency formats, in files under the root of the locales directory.

  • Use the short form of the I18n methods: I18n.t instead of I18n.translate and I18n.l instead of I18n.localize.

  • Use "lazy" lookup for the texts used in views. Let's say we have the following structure:

    en:
      users:
        show:
          title: "User details page"
    

    The value for users.show.title can be looked up in the template app/views/users/show.html.haml like this:

    = t '.title'
  • Use the dot-separated keys in the controllers and models instead of specifying the :scope option. The dot-separated call is easier to read and trace the hierarchy.

    # use this call
    I18n.t 'activerecord.errors.messages.record_invalid'
    
    # instead of this
    I18n.t :record_invalid, :scope => [:activerecord, :errors, :messages]
  • More detailed information about the Rails i18n can be found in the [Rails Guides] (http://guides.rubyonrails.org/i18n.html)

Assets

Use the assets pipeline to leverage organization within your application.

  • Reserve app/assets for custom stylesheets, javascripts, or images.
  • Third party code such as jQuery or bootstrap should be placed in vendor/assets.
  • When possible, use gemified versions of assets (e.g. jquery-rails).

Mailers

  • Name the mailers SomethingMailer. Without the Mailer suffix it isn't immediately apparent what's a mailer and which views are related to the mailer.

  • Provide both HTML and plain-text view templates.

  • Enable errors raised on failed mail delivery in your development environment. The errors are disabled by default.

    # config/environments/development.rb
    
    config.action_mailer.raise_delivery_errors = true
  • Use smtp.gmail.com for SMTP server in the development environment (unless you have local SMTP server, of course).

    # config/environments/development.rb
    
    config.action_mailer.smtp_settings = {
      address: 'smtp.gmail.com',
      # more settings
    }
  • Provide default settings for the host name.

    # config/environments/development.rb
    config.action_mailer.default_url_options = {host: "#{local_ip}:3000"}
    
    
    # config/environments/production.rb
    config.action_mailer.default_url_options = {host: 'your_site.com'}
    
    # in your mailer class
    default_url_options[:host] = 'your_site.com'
  • If you need to use a link to your site in an email, always use the _url, not _path methods. The _url methods include the host name and the _path methods don't.

    # wrong
    You can always find more info about this course
    = link_to 'here', url_for(course_path(@course))
    
    # right
    You can always find more info about this course
    = link_to 'here', url_for(course_url(@course))
  • Format the from and to addresses properly. Use the following format:

    # in your mailer class
    default from: 'Your Name <info@your_site.com>'
  • Make sure that the e-mail delivery method for your test environment is set to test:

    # config/environments/test.rb
    
    config.action_mailer.delivery_method = :test
  • The delivery method for development and production should be smtp:

    # config/environments/development.rb, config/environments/production.rb
    
    config.action_mailer.delivery_method = :smtp
  • When sending html emails all styles should be inline, as some mail clients have problems with external styles. This however makes them harder to maintain and leads to code duplication. There are two similar gems that transform the styles and put them in the corresponding html tags: premailer-rails3 and roadie.

  • Sending emails while generating page response should be avoided. It causes delays in loading of the page and request can timeout if multiple email are send. To overcome this emails can be send in background process with the help of delayed_job gem.

Bundler

  • Put gems used only for development or testing in the appropriate group in the Gemfile.

  • Use only established gems in your projects. If you're contemplating on including some little-known gem you should do a careful review of its source code first.

  • OS-specific gems will by default result in a constantly changing Gemfile.lock for projects with multiple developers using different operating systems. Add all OS X specific gems to a darwin group in the Gemfile, and all Linux specific gems to a linux group:

    # Gemfile
    group :darwin do
      gem 'rb-fsevent'
      gem 'growl'
    end
    
    group :linux do
      gem 'rb-inotify'
    end

    To require the appropriate gems in the right environment, add the following to config/application.rb:

    platform = RUBY_PLATFORM.match(/(linux|darwin)/)[0].to_sym
    Bundler.require(platform)
  • Do not remove the Gemfile.lock from version control. This is not some randomly generated file - it makes sure that all of your team members get the same gem versions when they do a bundle install.

Priceless Gems

One of the most important programming principles is "Don't reinvent the wheel!". If you're faced with a certain task you should always look around a bit for existing solutions, before unrolling your own. Here's a list of some "priceless" gems (all of them Rails 3.1 compliant) that are useful in many Rails projects:

  • active_admin - With ActiveAdmin the creation of admin interface for your Rails app is child's play. You get a nice dashboard, CRUD UI and lots more. Very flexible and customizable.
  • capybara - Capybara aims to simplify the process of integration testing Rack applications, such as Rails, Sinatra or Merb. Capybara simulates how a real user would interact with a web application. It is agnostic about the driver running your tests and currently comes with Rack::Test and Selenium support built in. HtmlUnit, WebKit and env.js are supported through external gems. Works great in combination with RSpec & Cucumber.
  • carrierwave - the ultimate file upload solution for Rails. Support both local and cloud storage for the uploaded files (and many other cool things). Integrates great with ImageMagick for image post-processing.
  • client_side_validations - Fantastic gem that automatically creates JavaScript client-side validations from your existing server-side model validations. Highly recommended!
  • compass-rails - Great gem that adds support for some css frameworks. Includes collection of sass mixins that reduces code of css files and help fight with browser incompatibilities.
  • cucumber-rails - Cucumber is the premium tool to develop feature tests in Ruby. cucumber-rails provides Rails integration for Cucumber.
  • devise - Devise is full-featured authentication solution for Rails applications. In most cases it's preferable to use devise to unrolling your custom authentication solution.
  • fabrication - a great fixture replacement (editor's choice).
  • factory_girl - an alternative to fabrication. Nice and mature fixture replacement. Spiritual ancestor of fabrication.
  • faker - handy gem to generate dummy data (names, addresses, etc).
  • feedzirra - Very fast and flexible RSS/Atom feed parser.
  • friendly_id - Allows creation of human-readable URLs by using some descriptive attribute of the model instead of its id.
  • guard - fantastic gem that monitors file changes and invokes tasks based on them. Loaded with lots of useful extension. Far superior to autotest and watchr.
  • haml-rails - haml-rails provides Rails integration for Haml.
  • haml - HAML is a concise templating language, considered by many (including yours truly) to be far superior to Erb.
  • kaminari - Great paginating solution.
  • machinist - Fixtures aren't fun. Machinist is.
  • rspec-rails - RSpec is a replacement for Test::MiniTest. I cannot recommend highly enough RSpec. rspec-rails provides Rails integration for RSpec.
  • simple_form - once you've used simple_form (or formtastic) you'll never want to hear about Rails's default forms. It has a great DSL for building forms and no opinion on markup.
  • simplecov-rcov - RCov formatter for SimpleCov. Useful if you're trying to use SimpleCov with the Hudson contininous integration server.
  • simplecov - code coverage tool. Unlike RCov it's fully compatible with Ruby 1.9. Generates great reports. Must have!
  • slim - Slim is a concise templating language, considered by many far superior to HAML (not to mention Erb). The only thing stopping me from using Slim massively is the lack of good support in major editors/IDEs. Its performance is phenomenal.
  • spork - A DRb server for testing frameworks (RSpec / Cucumber currently) that forks before each run to ensure a clean testing state. Simply put it preloads a lot of test environment and as consequence the startup time of your tests in greatly decreased. Absolute must have!
  • sunspot - SOLR powered full-text search engine.

This list is not exhaustive and other gems might be added to it along the road. All of the gems on the list are field tested, have active development and community and are known to be of good code quality.

Flawed Gems

This is a list of gems that are either problematic or superseded by other gems. You should avoid using them in your projects.

  • rmagick - this gem is notorious for its memory consumption. Use minimagick instead.
  • autotest - old solution for running tests automatically. Far inferior to guard and watchr.
  • rcov - code coverage tool, not compatible with Ruby 1.9. Use SimpleCov instead.
  • therubyracer - the use of this gem in production is strongly discouraged as it uses a very large amount of memory. I'd suggest using Mustang instead.

This list is also a work in progress. Please, let me know if you know other popular, but flawed gems.

Managing processes

  • If your projects depends on various external processes use foreman to manage them.

Further Reading

There are a few excellent resources on Rails style, that you should consider if you have time to spare:

Spread the Word

It's a complementary guide to the already existing community-driven Ruby coding style guide.