Rails Environments and Configuration - The Rails 4 Way (2014)

The Rails 4 Way (2014)

Chapter 1. Rails Environments and Configuration

[Rails] gained a lot of its focus and appeal because I didn’t try to please people who didn’t share my problems. Differentiating between production and development was a very real problem for me, so I solved it the best way I knew how.

—David Heinemeier Hansson

Rails applications are preconfigured with three standard modes of operation: development, test, and production. These modes are basically execution environments and have a collection of associated settings that determine things such as which database to connect to, and whether the classes of your application should be reloaded with each request. It is also simple to create your own custom environments if necessary.

The current environment can be specified via the environment variable RAILS_ENV, which names the desired mode of operation and corresponds to an environment definition file in the config/environments folder. You can also set the environment variable RACK_ENV or as a last resort you may rely on the default being development. Since this environment setting governs some of the most fundamental aspects of Rails, such as class loading, in order to really understand the Rails way you should understand its environment settings.

In this chapter, we start by covering Bundler, a tool that manages gem dependencies for your Ruby application. It takes a gem manifest file and is able to fetch, download, and install the gems in the manifest, and all child dependencies. Then we move on to how Rails starts up and handles requests, by examining scripts such as boot.rb and application.rb and the settings that make up the three standard environment settings (modes). We also cover some of the basics of defining your own environments, and why you might choose to do so.

Note that this book is not written with absolute newcomers to Rails in mind. To make the most out of this book, you should already be at least somewhat familiar with how to bootstrap a Rails application and the meaning of MVC. If you are not, I recommend that you first take advantage of the excellent Ruby on Rails Tutorial website by Michael Hartl, another Professional Ruby Series author.

1.1 Bundler

Bundler is not a technology that is specific to Rails 4, but it is the preferred way to manage your application’s gem dependencies. Applications generated with Rails 4 use Bundler automatically, and you should not need to install the bundler gem separately since it’s a dependency of Rails itself.

Since we believe that you should use Bundler, figuring out how to not use Bundler is left as an exercise for adventurous and/or nonconformist readers.

One of the most important things that Bundler does is dependency resolution on the full list of gems specified in your configuration, all at once. This differs from the one-at-a-time dependency resolution approach employed by Rubygems and previous versions of Rails, which can (and often did) result in the following hard-to-fix problem:

Assume that your system had the following Rubygem versions installed.

activesupport 4.0.2

activesupport 3.2.11

activemerchant 1.29.3

rails 3.2.11

It turns out that activemerchant 1.29.3 depends on activesupport >= 2.3.14 therefore when you load it using the gem command (from the RubyGems library) like this

gem 'activemerchant', '1.29.3'

it results in the loading of activemerchant, as well as the latest compatible versions of its dependencies, including the activesupport 4.0.2 gem, since it is greater than or equal to version 2.3.14. Subsequently, trying to load rails itself with

gem 'rails', '3.2.11'

results in the following exception at runtime.

can't activate activesupport (= 3.2.11, runtime)

for ["rails-3.2.11"], already activated

activesupport-4.0.2 for ["activemerchant-1.29.3"]

The exception happens because activemerchant has a broader dependency that results in the activation of a version of Active Support that does not satisfy the more narrow dependency of the older version of Rails. Bundler solves this problem by evaluating all dependencies at once and figuring out exactly the right versions of gems to load.

For an interesting perspective concerning the way that Bundler was conceived, make sure to read Yehuda’s blog post on the subject.

1.1.1 Gemfile

Located in the root of your Rails project directory, is a Ruby-based gem manifest file named Gemfile. The Gemfile specifies all dependencies of your Rails app, including the version of Rails being used. The basic syntax for the Gemfile is super simple:

gem 'kaminari'

gem 'nokogiri'

To load a dependency only in a specific environment, place it in a group block specifying one or more environment names as symbols:

group :development do

gem 'pry-rails'

end

group :test do

gem 'capybara'

gem 'database_cleaner'

end

group :development, :test do

gem 'rspec-rails'

gem 'factory_girl_rails'

end

tip

Upgrading from Rails 3

If you’re upgrading from Rails 3, note that Rails 4 no longer uses the assets group for asset pipeline related gems. You will need to move all assets grouped gems inline.

The gem directive takes an optional second argument describing the version of the Rubygem desired. Leaving the version argument off will simply get the latest available stable version, which may not be the latest version available. To include a release candidate or a pre-release gem you’ll need to specify the version explicitly.

The format of the version argument matches the RubyGem versioning scheme to which you should already be accustomed.

gem 'nokogiri', '1.5.6'

gem 'pry-rails', '> 0.2.2'

gem 'decent_exposure', '~> 2.0.1'

gem 'draper', '1.0.0.beta6'

You can find full instructions on how to craft a version string in the RubyGems documentation.

Occasionally, the name of the gem that should be used in a require statement is different than the name of that gem in the repository. In those cases, the :require option solves this simply and declaratively right in the Gemfile.

gem 'webmock', require: 'webmock/rspec'

1.1.1.1 Loading Gems Directly From a Git Repository

Until now we have been loading our gems from https://rubygems.org. It is possible to specify a gem by its source repository as long as it has a .gemspec file in the root directory. Just add a :git option to the call to gem.

gem 'carrierwave', git: 'git@github.com:carrierwaveuploader/carrierwave.git'

If the gem source repository is hosted on GitHub and is public, you can use the :github shorthand.

gem 'carrierwave', github: 'carrierwaveuploader/carrierwave'

Gemspecs with binaries or C extensions are also supported.

gem 'nokogiri', git: 'git://github.com/tenderlove/nokogiri.git'

If there is no .gemspec file at the root of a gem’s git repository, you must tell Bundler which version to use when resolving its dependencies.

gem 'deep_merge', '1.0', git: 'git://github.com/peritor/deep_merge.git'

It’s also possible to specify that a git repository contains multiple .gemspec files and should be treated as a gem source. The following example does just that for the most common git repository that fits the criteria, the Rails codebase itself. (Note: You should never actually need to put the following code in a Gemfile for one of your Rails applications!)

git 'git://github.com/rails/rails.git'

gem 'railties'

gem 'action_pack'

gem 'active_model'

Additionally, you can specify that a git repository should use a particular ref, branch, or tag as options to the git directive:

git 'git://github.com/rails/rails.git',

ref: '4aded'

git 'git://github.com/rails/rails.git',

branch: '3-2-stable'

git 'git://github.com/rails/rails.git',

tag: 'v3.2.11'

Specifying a ref, branch, or tag for a git repository specified inline uses the same option syntax.

gem 'nokogiri', git: 'git://github.com/tenderlove/nokogiri.git', ref: '0eec4'

1.1.1.2 Loading Gems From the File System

You can use a gem that you are actively developing on your local workstation using the :path option.

gem 'nokogiri', path: '~/code/nokogiri'

1.1.2 Installing Gems

Every time you modify the Gemfile, or more specifically, if you introduce dependencies not yet installed, invoke the install command to ensure that all the dependencies in your Gemfile are available to your Rails application.1

$ bundle install

Fetching gem metadata from https://rubygems.org/.........

Fetching gem metadata from https://rubygems.org/..

Installing rake (10.1.0)

Installing i18n (0.6.9)

Installing minitest (4.7.5)

Installing multi_json (1.8.2)

Installing atomic (1.1.14)

Installing thread_safe (0.1.3)

Installing tzinfo (0.3.38)

Installing activesupport (4.0.2)

Installing builder (3.1.4)

Installing erubis (2.7.0)

Installing rack (1.5.2)

Installing rack-test (0.6.2)

Installing actionpack (4.0.2)

Installing mime-types (1.25.1)

Installing polyglot (0.3.3)

Installing treetop (1.4.15)

Installing mail (2.5.4)

Installing actionmailer (4.0.2)

Installing activemodel (4.0.2)

Installing activerecord-deprecated_finders (1.0.3)

Installing arel (4.0.1)

Installing activerecord (4.0.2)

Installing coffee-script-source (1.6.3)

Installing execjs (2.0.2)

Installing coffee-script (2.2.0)

Installing thor (0.18.1)

Installing railties (4.0.2)

Installing coffee-rails (4.0.1)

Installing hike (1.2.3)

Installing jbuilder (1.5.2)

Installing jquery-rails (3.0.4)

Installing json (1.8.1)

Installing bundler (1.3.5)

Installing tilt (1.4.1)

Installing sprockets (2.10.1)

Installing sprockets-rails (2.0.1)

Installing rails (4.0.2)

Installing rdoc (3.12.2)

Installing sass (3.2.12)

Installing sass-rails (4.0.1)

Installing sdoc (0.3.20)

Installing sqlite3 (1.3.8)

Installing turbolinks (1.3.1)

Installing uglifier (2.3.2)

Your bundle is complete!

Use `bundle show [gemname]` to see where a bundled gem is installed.

The install command updates all dependencies named in your Gemfile to the latest versions that do not conflict with other dependencies.

You can opt to install dependencies, except those in specified groups using the --without option.

$ bundle install --without development test

$ bundle install --without test

1.1.3 Gem Locking

Every time you run bundle install or bundle update, Bundler calculates the dependency tree for your application and stores the results in a file named Gemfile.lock. From that point on Bundler will only load specific versions of gems that you are using at the moment that the Gemfile was locked, versions that you know will work well with your application.

information

Note

The Gemfile.lock file should always be checked into version control, to ensure every machine running the application uses the exact same versions of gems.2

To illustrate the importance of this, imagine the Gemfile.lock is missing and the application is being deployed to production. Since the dependency tree is non-existent, Bundler has to resolve all of the gems from the Gemfile on that machine. This in result may install newer gem versions than you tested against, causing unforeseen issues.

1.1.4 Packaging Gems

You can package up all your gems in the vendor/cache directory inside of your Rails application.

$ bundle package

Running bundle install --local in an application with packaged gems will use the gems in the package and skip connecting to rubygems.org or any other gem sources. You can use this to avoid external dependencies at deploy time, or if you depend on private gems that are not available in any public repository.

information

Making gem dependencies available to non-Rails scripts

Non-Rails scripts must be executed with bundle exec in order to get a properly initialized RubyGems environment.

$ bundle exec guard

As of Rails 4, generating a new application will result in the creation of binstubs for Rails executables, located in the bin folder. A binstub is a script containing an executable that runs in the context of the bundle. This means one does not have to prefix bundle exec each time a Rails specific executable is invoked. Binstubs are also first class citizens in Rails 4, and should be added into your version control system like any other source code file.

By default, the following stubs are available on every new Rails 4 project:

· bin/bundle

· bin/rails

· bin/rake

· bin/spring

tip

Upgrading from Rails 3

If you are upgrading from Rails 3 and have generated binstubs using Bundler in the past, you must upgrade your binstubs by running the following commands:

1 bundle config --delete bin # Turn off Bundler's stub generator

2 rake rails:update:bin # Use the new Rails 4 executables

3 git add bin # Add bin/ to source control

To add a binstub of a commonly used executable in your bundle, invoke bundle binstubs some-gem-name. To illustrate, consider the following example:

$ bundle binstubs guard

which creates a binstub for guard in the bin folder.

1 #!/usr/bin/env ruby

2 #

3 # This file was generated by Bundler.

4 #

5 # The application 'guard' is installed as part of a gem, and

6 # this file is here to facilitate running it.

7 #

8

9 require 'pathname'

10 ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",

11 Pathname.new(__FILE__).realpath)

12

13 require 'rubygems'

14 require 'bundler/setup'

15

16 load Gem.bin_path('guard', 'guard')

Using binstubs, scripts can be executed directly from the bin directory.

1 $ bin/guard

1.2 Startup and Application Settings

Whenever you start a process to handle requests with Rails (such as with rails server), one of the first things that happens is that config/boot.rb is loaded.

There are three files involved in setting up the entire Rails stack:

config/boot.rb

sets up Bundler and load paths.

config/application.rb

loads rails gems, gems for the specified Rails.env, and configures the application.

config/environment.rb

runs all initializers.

All three are run when you need the whole Rails environment loaded. That’s what’s done by runner, console, server, etc.

1.2.1 config/application.rb

The file config/application.rb is the home to your Rails application settings, and it’s the only file required at the top of config/environment.rb.

Let’s go step by step through the settings provided in the default config/application.rb file that you’ll find in a newly created Rails application. By the way, as you’re reading through the following sections, make a mental note to yourself that changes to these files require a server restart to take effect.

The next lines of config/application.rb are where the wheels really start turning, once config/boot.rb is loaded:

require File.expand_path('../boot', __FILE__)

Note that the boot script is generated as part of your Rails application, but you won’t usually need to edit it.

Getting back to config/application.rb we find the following line:

require 'rails/all'

You also have the ability to easily cherry-pick only the components needed by your application.

1 # To pick the frameworks you want, remove 'require "rails/all"'

2 # and list the framework railties that you want:

3 #

4 # require "active_model/railtie"

5 # require "active_record/railtie"

6 # require "action_controller/railtie"

7 # require "action_mailer/railtie"

8 # require "action_view/railtie"

9 # require "sprockets/railtie"

10 # require "rails/test_unit/railtie"

The main configuration of our application follows, which in Rails 4 gets its own module and class:

1 moduleTimeAndExpenses

2 classApplication < Rails::Application

3 # Settings in config/environments/* take precedence over those

4 # specified here. Application configuration should go into files

5 # in config/initializers

6 # -- all .rb files in that directory are automatically loaded.

The creation of a module specifically for your application is part of the groundwork for supporting running multiple Rails applications in the same process.

1.2.1.1 Time Zones

The default time zone for Rails 4 applications is UTC. If the business domain of your application is sensitive to knowing exactly what time zone the server is in, then you can use the following setting to override the default:

# Set Time.zone default to the specified zone and make Active Record

# auto-convert to this zone.

# Run "rake -D time" for a list of tasks for finding time zone names.

config.time_zone = 'Central Time (US & Canada)'

tip

Juanito says…

rake time:zones:all will list all the timezones Rails knows about.

1.2.1.2 Localization

Rails features localization support via locale files and is covered in great detail in Chapter 11, “All About Helpers” in the TranslationHelper and I18n API sections.

The default locale is :en and can be overridden in your configuration.

# The default locale is :en and all translations from

# config/locales/*.rb,yml are auto loaded.

# config.i18n.load_path += Dir[Rails.root.join('my', 'locales',

# '*.{rb,yml}')]

# config.i18n.default_locale = :de

1.2.1.3 Generator Default Settings

Rails generator scripts make certain assumptions about your tool chain. Setting the correct values here means having to type less parameters on the command line. For instance, to use RSpec without fixtures and Haml as the template engine, our settings would look like:

# Configure generators values. Many other options are available,

# be sure to check the documentation.

config.generators do |g|

g.template_engine :haml

g.test_framework :rspec, fixture: false

end

Note that Rubygems such as rspec-rails and factory_girl_rails handle this for you automatically.

1.2.2 Initializers

Rails 2 introduced the concept of breaking out configuration settings into their own small ruby files under the config/initializers directory, where they are automatically loaded at startup. You can add configuration settings for your own application by adding ruby files to the initializers directory. The following seven initializers are included by default in all Rails applications.

1.2.2.1 Backtrace Silencers

Nobody likes really long exception backtraces, except maybe Java programmers. Rails has a mechanism for reducing the size of backtraces by eliminating lines that don’t really add anything to your debugging.

The backtrace_silencers.rb initializer lets you modify the way that backtraces are shortened. I’ve found it useful to remove backtrace entries for noisy libraries, but removing all silencers is usually never needed during normal application development.

1 # You can add backtrace silencers for libraries that you're using but

2 # don't wish to see in your backtraces.

3 Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }

4

5 # You can also remove all the silencers if you're trying to debug a

6 # problem that might stem from framework code.

7 Rails.backtrace_cleaner.remove_silencers!

1.2.2.2 Filter Parameter Logging

When a request is made to your application, by default Rails logs details such as the request path, HTTP method, IP Address, and parameters. If an attacker somehow gained access to your logs, they may be able to view sensitive information, like passwords and credit card numbers.

The filter_parameter_logging.rb initializer let’s you specify what request parameters should be filtered from your log files. If Rails receives a request parameter included in the filter_parameters collection, it will mark it as [FILTERED] in your logs.

# Configure sensitive parameters which will be filtered from the log file.

Rails.application.config.filter_parameters += [:password]

1.2.2.3 Inflections

Rails has a class named Inflector whose responsibility is to transform strings (words) from singular to plural, class names to table names, modularized class names to ones without, and class names to foreign keys, etc. (Some of its operations have funny names, such as dasherize.)

The default inflections for pluralization and singularization of uncountable words are kept in an interesting file inside the ActiveSupport gem, named inflections.rb.

Most of the time the Inflector class does a decent job of figuring out the pluralized table name for a given class, but occasionally it won’t. This is one of the first stumbling blocks for many new Rails users, but it is not necessary to panic. With a little ad hoc testing beforehand, it’s easy to find out how Inflector will react to certain words. We just need to use the Rails console, which by the way is one of the best things about working in Rails.

You fire up the console from your terminal with the rails console command.

$ rails console

>> ActiveSupport::Inflector.pluralize "project"

=> "projects"

>> ActiveSupport::Inflector.pluralize "virus"

=> "viri"

>> "pensum".pluralize # Inflector features are mixed into String

by default

=> "pensums"

As you can see in the example, Inflector tries to be smart, pluralizing virus as viri; but if you know your Latin, you have already noticed that the plural pensum should actually be pensa. Needless to say, the inflector does not know Latin.3

However, you can teach the inflector new tricks by adding new pattern rules, by pointing out an exception, or by declaring certain words unpluralizable. The preferred place to do that is inside the config/initializers/inflections.rb file, where a commented example is already provided:

1 ActiveSupport::Inflector.inflections(:en) do |inflect|

2 inflect.plural /^(ox)$/i, '\1en'

3 inflect.singular /^(ox)en/i, '\1'

4 inflect.irregular 'person', 'people'

5 inflect.uncountable %w( fish sheep )

6 end

The file activesupport/test/inflector_test_cases.rb has a long list of pluralizations correctly handled by Inflector. I found some of them pretty interesting, such as:

1 "datum" => "data",

2 "medium" => "media",

3 "analysis" => "analyses"

1.2.2.4 Custom MIME Types

Rails supports a standard set of MIME types (*/*, text/html, text/plain, text/javascript, text/css, text/calendar, text/csv, application/xml, application/rss+xml, application/atom+xml, application/x-yaml, multipart/form-data, application/x-www-form-urlencoded, application/json)

Short name

respond_to symbol

Aliases and Explanations

text/html

:html, :xhtml

application/xhtml+xml

text/plain

:text, :txt

text/javascript

:js

application/javascript,

application/x-javascript

text/css

:css

Cascading style sheets

text/calendar

:ics

iCalendar format for sharing

meeting requests and tasks

text/csv

:csv

Comma-separated values

application/xml

:xml

text/xml, application/x-xml

application/rss+xml

:rss

Really Simple Syndication format

for web feeds

application/atom+xml

:atom

Atom Syndication Format for web

feeds

application/x-yaml

:yaml

text/yaml - The human-readable

data serialization format

application/x-www-form-

:url_encoded_form

The default content type of HTML

urlencoded

forms

multipart/form-data

:multipart_form

Used for HTML forms that contain

files, non-ASCII data, and

binary data

application/json

:json

text/x-json,

application/jsonrequest -

JavaScript Object Notation

If your application needs to respond to other MIME types, you can register them in the mime_types.rb initializer

# Add new mime types for use in respond_to blocks:

# Mime::Type.register "text/richtext", :rtf

# Mime::Type.register_alias "text/html", :iphone

1.2.2.5 Session Store

As of Rails 4, session cookies are encrypted by default using the new encrypted cookie store. The session_store.rb initializer configures the session store of the application, by setting its session store type and key.

Rails.application.config.session_store :cookie_store,

key: '_example_session'

The session cookies are signed using the secret_key_base set in the config/secrets.yml configuration file. If you are really paranoid, you can change the secret key in config/secrets.yml or run rake secret to generate a new one automatically.

1.2.2.6 Wrap Parameters

Introduced in Rails 3.1, the wrap_parameters.rb initializer configures your application to work with JavaScript MVC frameworks, such as Backbone.js out of the box.

# Be sure to restart your server when you modify this file.

# This file contains settings for ActionController::ParamsWrapper which

# is enabled by default.

# Enable parameter wrapping for JSON. You can disable this by setting

# :format to an empty array.

ActiveSupport.on_load(:action_controller) do

wrap_parameters format: [:json] if respond_to?(:wrap_parameters)

end

# To enable root element in JSON for ActiveRecord objects.

# ActiveSupport.on_load(:active_record) do

# self.include_root_in_json = true

# end

When submitting JSON parameters to a controller, Rails will wrap the parameters into a nested hash, with the controller’s name being set as the key. To illustrate, consider the following JSON:

{"title": "The Rails 4 Way"}

If a client submitted the above JSON to a controller named ArticlesController, Rails would nest the params hash under the key “article”. This ensures the setting of model attributes from request parameters is consistent with the convention used when submitting from Rails form helpers.

{"title": "The Rails 4 Way", "article" => {"title": "The Rails 4 Way"}}

1.2.3 Additional Configuration

That does it for the configuration options for which we get examples in the default config/application.rb and the standard initializers. There are additional options, which you can add in additional initializer files.

1.2.3.1 Load Path Modifications

By default, Rails looks for code in a number of standard directories, including all nested directories under app, such as app/models. This is referred to collectively as the load path. You can add other directories to the load path using the following code:

# Custom directories with classes and modules you want to be autoloadable

# config.autoload_paths += %W(#{config.root}/extras)

In case you didn’t know, the %W functions as a whitespace-delimited array literal and is used quite often in the Rails codebase for convenience.

1.2.3.2 Log-Level Override

The default log level is :debug and you can override it if necessary.

# Force all environments to use the same logger level

# (by default production uses :info, the others :debug)

config.log_level = :debug

This book covers use of the Rails logger in-depth later on in this chapter.

1.2.3.3 Schema Dumper

Every time you run tests, Rails dumps the schema of your development database and copies it to the test database using an auto generated schema.rb script. It looks very similar to an Active Record migration script; in fact, it uses the same API.

You might find it necessary to revert to the older style of dumping the schema using SQL, if you’re doing things that are incompatible with the schema dumper code (see the comment).

# Use SQL instead of Active Record's schema dumper when creating the

# test database. This is necessary if your schema can't be completely

# dumped by the schema dumper, for example, if you have constraints

# or db-specific column types

config.active_record.schema_format = :sql

Remember we said that the value of the RAILS_ENV environment variable dictates which additional environment settings are loaded next? So now let’s review the default settings for each of Rails’ standard modes.

1.2.3.4 Console

New to Rails 4 is the ability to supply a block to console, a method that is only evaluated when the Rails environment is loaded through the console. This allows you to set console-specific configurations, such as using Pry over IRB. Put this in your config/application.rb:

1 console do

2 # this block is called only when running console,

3 # so we can safely require pry here

4 require "pry"

5 config.console = Pry

6 end

Note that the pry gem must be included in your Gemfile.

1.2.4 Spring Application Preloader

As of version 4.1, Rails ships with an application preloader named Spring4. In doing so, during development, your application will be remain running in the background. This speeds up development by eliminating the need to boot up Rails every time you execute tests, or run a rake task.

While running, Spring monitors folders config and initializers for changes. If a file within those folders are changed, Spring will automatically restart your application. Spring will also restart if any gem dependencies are changed during development.

To demonstrate the speed increase Spring provides, let’s run the same rake task in both Rails 4.0 and and a preloaded 4.1 application:

1 # Rails 4.0

2 $ time bin/rake about

3 ...

4 bin/rake about 1.20s user 0.36s system 22% cpu 6.845 total

5

6 # Rails 4.1

7 $ time bin/rake about

8 ...

9 bin/rake about 0.08s user 0.04s system 32% cpu 0.370 total

The preloaded Rails environment using Spring provided a savings of over 6 seconds.

1.3 Development Mode

Development is Rails’ default mode and the one in which you will spend most of your time as a developer. This section contains an in-depth explanation of each setting.

# File: config/environments/development.rb

Rails.application.configure do

# Settings specified here will take precedence over those in

# config/application.rb.

1.3.1 Automatic Class Reloading

One of the signature benefits of using Rails is the quick feedback cycle whenever you’re working in development mode. Make changes to your code, hit Reload in the browser, and Shazam! Magically, the changes are reflected in your application. This behavior is governed by theconfig.cache_classes setting:

# In the development environment your application's code is reloaded on

# every request. This slows down response time but is perfect for

# development since you don't have to restart the web server when you

# make code changes.

config.cache_classes = false

Without getting into too much nitty-gritty detail, when the config.cache_classes setting is true, Rails will use Ruby’s require statement to do its class loading, and when it is false, it will use load instead.

When you require a Ruby file, the interpreter executes and caches it. If the file is required again (as in subsequent requests), the interpreter ignores the require statement and moves on. When you load a Ruby file, the interpreter executes the file again, no matter how many times it has been loaded before.

Now it’s time to examine the Rails class-loading behavior a bit more in depth, because sometimes you won’t be able to get certain things to reload automatically and it will drive you crazy unless you understand how class loading works!

1.3.1.1 The Rails Class Loader

In plain old Ruby, a script file doesn’t need to be named in any particular way that matches its contents. In Rails, however, you’ll notice that there’s almost always a direct correlation between the name of a Ruby file and the class or module contained within. Rails takes advantage of the fact that Ruby provides a callback mechanism for missing constants. When Rails encounters an undefined constant in the code, it uses a class loader routine based on file-naming conventions to find and require the needed Ruby script.

How does the class loader know where to search? We already covered it earlier in the chapter where we discussed the role of initializer.rb in the Rails startup process. Rails has the concept of load paths, and the default load paths include the base directories of just about anywhere you would think of adding code to your Rails application.

Want to see the contents of your project’s load path? Just fire up the console and type $LOAD_PATH

$ rails console

Loading development environment.

>> $LOAD_PATH

=> ["/usr/local/lib/ruby/... # about 20 lines of output

I snipped the console output to save space. A typical Rails project load path will usually have 60 or more items in its load path. Try it and see.

1.3.1.2 Rails, Modules, and Auto-Loading Code

Normally in Ruby, when you want to include code from another file in your application, you have to include a require statement. However, Rails enhances Ruby’s default behavior by establishing a simple convention that enables Rails to automatically load your code in most cases. If you’ve used the Rails console at all, you’ve already seen this behavior in action: You never have to explicitly require anything!

This is how it works: If Rails encounters a class or module in your code that is not already defined, Rails uses the following convention to guess which files it should require to load that module or class:

If the class or module is not nested, insert an underscore between the constant’s names and require a file of this name. For example:

· EstimationCalculator becomes require "estimation_calculator"

· KittTurboBoost becomes require "kitt_turbo_boost"

If the class or module is nested, Rails inserts an underscore between each of the containing modules and requires a file in the corresponding set of subdirectories. For example:

· MacGyver::SwissArmyKnife becomes require "mac_gyver/swiss_army_knife"

· Example::ReallyRatherDeeply::NestedClass becomes require "example/really_rather_deeply/nested_class" and if not already loaded, Rails would expect to find it in a file called nested_class.rb, in a directory called really_rather_deeply, itself in the directory example of which can be found somewhere in Ruby’s load path (e.g., one of the app subdirectories, lib, or a plugin’s lib directory).

The bottom line is that you should rarely need to explicitly load Ruby code in your Rails applications (using require) if you follow the naming conventions.

1.3.2 Eager Load

To speed up the boot time of starting a Rails server during development, code is no longer eager loaded. This behavior is governed by the config.eager_load setting:

# Do not eager load code on boot.

config.eager_load = false

In your production environment, you will want this set to true, as it copies most of your application in memory. This provides a performance increase to web servers that copy on write, such as Unicorn.

1.3.3 Error Reports

Requests from localhost, like when you’re developing, generate useful error messages that include debugging information such as a line number where the error occurred and a backtrace. Setting consider_all_requests_local to true causes Rails to display those developer-friendly error screens even when the machine making the request is remote.

config.consider_all_requests_local = true

1.3.4 Caching

You normally do not want caching behavior when you’re in development mode. The only time you do want it is if you’re actually testing caching.

config.action_controller.perform_caching = true # for testing in development mode

Remember to set it back to false when you’re done testing. Unexpected caching behavior can be very tricky to figure out.

1.3.5 Raise Delivery Errors

Rails assumes that you don’t want Action Mailer to raise delivery exceptions in development mode, so based on the config.action_mailer.raise_delivery_errors settings, it will swallow them. Mailing capabilities don’t necessarily work in an average development workstation, particularly on Windows and other platforms that lack sendmail.

# Don't care if the mailer can't send.

config.action_mailer.raise_delivery_errors = false

If you actually want to send mail while in development mode as part of debugging or ad-hoc testing, then you probably want to toggle this setting.

discussion

Xavier says…

I find it handy to set config.action_mailer.perform_deliveries = false in development. No delivery attempt is performed, but you can still see the mail in the log file to check it looks good, copy account activation URLs, etc.

1.3.6 Deprecation Notices

Deprecations warnings are very useful to let you know when you should stop using a particular piece of functionality. The configuration setting config.active_support.deprecation allows you to set how you would like to receive deprecation warnings. In development mode, by default all deprecation warnings will appear in the development log.

# Print deprecation notices to the Rails logger.

config.active_support.deprecation = :log

1.3.7 Pending Migrations Error Page

In previous versions of Rails, if pending migrations needed to be run, the web server would fail to start. As of Rails 4, a new error page is displayed instead, indicating to developers that they should run rake db:migrate RAILS_ENV=development to resolve the issue.

# Raise an error on page load if there are pending migrations

config.active_record.migration_error = :page_load

1.3.8 Assets Debug Mode

Rails 3.1 introduced us to the Asset Pipeline, a framework to concatenate and minify JavaScript and CSS assets. By default in development mode, JavaScript and CSS files are served separately in the order they were specified in their respective manifest files. Setting config.assets.debug tofalse, would result in Sprockets concatenating and running preprocessors on all assets.

# Debug mode disables concatenation and preprocessing of assets.

config.assets.debug = true

The Asset Pipeline is covered in detailed in Chapter 20, Asset Pipeline.

1.4 Test Mode

Whenever you run Rails in test mode, that is, the value of the RAILS_ENV environment value is test, then the following settings are in effect (reproduced here for reference purposes):

1 # File: config/environments/test.rb

2 Rails.application.configure do

3 # Settings specified here will take precedence over those in

4 # config/application.rb.

5

6 # The test environment is used exclusively to run your application's

7 # test suite. You never need to work with it otherwise. Remember that

8 # your test database is "scratch space" for the test suite and is wiped

9 # and recreated between test runs. Don't rely on the data there!

10 config.cache_classes = true

11

12 # Do not eager load code on boot. This avoids loading your whole

13 # application just for the purpose of running a single test. If you are

14 # using a tool that preloads Rails for running tests, you may have to set

15 # it to true.

16 config.eager_load = false

17

18 # Configure static asset server for tests with Cache-Control for

19 # performance.

20 config.serve_static_assets = true

21 config.static_cache_control = "public, max-age=3600"

22

23 # Show full error reports and disable caching.

24 config.consider_all_requests_local = true

25 config.action_controller.perform_caching = false

26

27 # Raise exceptions instead of rendering exception templates.

28 config.action_dispatch.show_exceptions = false

29

30 # Disable request forgery protection in test environment.

31 config.action_controller.allow_forgery_protection = false

32

33 # Tell Action Mailer not to deliver emails to the real world.

34 # The :test delivery method accumulates sent emails in the

35 # ActionMailer::Base.deliveries array.

36 config.action_mailer.delivery_method = :test

37

38 # Print deprecation notices to the stderr.

39 config.active_support.deprecation = :stderr

40 end

Most people get by without ever needing to modify their test environment settings.

information

Custom Environments

If necessary, you can create additional environments for your Rails app to run by cloning one of the existing environment files in the config/environments directory of your application. The most common use case for custom environments is in setting up additional production configurations, such as for staging and QA deployments. Do you have access to the production database from your development workstation? Then a triage environment might make sense. Use the normal environment settings for development mode, but point its database connection to a production database server. It’s a potentially life-saving combination when you need to quickly diagnose issues in production.

1.5 Production Mode

Finally, production mode is what you want your Rails application running in whenever it is deployed to its hosting environment and serving public requests. There are a number of significant ways that production mode differs from the other modes, not least of which is the speed boost you get from not reloading all of your application classes for every request.

1 # File: config/environments/production.rb

2 Rails.application.configure do

3 # Settings specified here will take precedence over those in

4 # config/application.rb.

5

6 # Code is not reloaded between requests.

7 config.cache_classes = true

8

9 # Eager load code on boot. This eager loads most of Rails and

10 # your application in memory, allowing both thread web servers

11 # and those relying on copy on write to perform better.

12 # Rake tasks automatically ignore this option for performance.

13 config.eager_load = true

14

15 # Full error reports are disabled and caching is turned on.

16 config.consider_all_requests_local = false

17 config.action_controller.perform_caching = true

18

19 # Enable Rack::Cache to put a simple HTTP cache in front of your

20 # application

21 # Add `rack-cache` to your Gemfile before enabling this.

22 # For large-scale production use, consider using a caching reverse proxy

23 # like nginx, varnish or squid.

24 # config.action_dispatch.rack_cache = true

25

26 # Disable Rails's static asset server (Apache or nginx will

27 # already do this).

28 config.serve_static_assets = false

29

30 # Compress JavaScripts and CSS.

31 config.assets.js_compressor = :uglifier

32 # config.assets.css_compressor = :sass

33

34 # Whether to fallback to assets pipeline if a precompiled

35 # asset is missed.

36 config.assets.compile = false

37

38 # Generate digests for assets URLs.

39 config.assets.digest = true

40

41 # Version of your assets, change this if you want to expire

42 # all your assets.

43 config.assets.version = '1.0'

44

45 # Specifies the header that your server uses for sending files.

46 # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache

47 # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'

48 # for nginx

49

50 # Force all access to the app over SSL, use Strict-Transport-Security,

51 # and use secure cookies.

52 # config.force_ssl = true

53

54 # Set to :debug to see everything in the log.

55 config.log_level = :info

56

57 # Prepend all log lines with the following tags.

58 # config.log_tags = [ :subdomain, :uuid ]

59

60 # Use a different logger for distributed setups.

61 # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)

62

63 # Use a different cache store in production.

64 # config.cache_store = :mem_cache_store

65

66 # Enable serving of images, stylesheets, and JavaScripts from an

67 # asset server.

68 # config.action_controller.asset_host = "http://assets.example.com"

69

70 # Precompile additional assets.

71 # application.js, application.css, and all non-JS/CSS in app/assets

72 # folder are already added.

73 # config.assets.precompile += %w( search.js )

74

75 # Ignore bad email addresses and do not raise email delivery errors.

76 # Set this to true and configure the email server for immediate delivery

77 # to raise delivery errors.

78 # config.action_mailer.raise_delivery_errors = false

79

80 # Enable locale fallbacks for I18n (makes lookups for any locale fall

81 # back to the I18n.default_locale when a translation can not be found).

82 config.i18n.fallbacks = true

83

84 # Send deprecation notices to registered listeners.

85 config.active_support.deprecation = :notify

86

87 # Disable automatic flushing of the log to improve performance.

88 # config.autoflush_log = false

89

90 # Use default logging formatter so that PID and timestamp

91 # are not suppressed.

92 config.log_formatter = ::Logger::Formatter.new

93 end

1.5.1 Assets

In production mode, assets are by default precompiled by the Asset Pipeline. All files included in application.js and application.css asset manifests are compressed and concatenated into their respective files of the same name, located in the public/assets folder.

If an asset is requested that does not exist in the public/assets folder, Rails will throw an exception. To enable live asset compilation fallback on production, set config.assets.compile to true.

The application.js and application.css manifest files are the only JavaScript/Stylesheets included during the asset pipeline precompile step. To include additional assets, specify them using the config.assets.precompile configuration setting.

config.assets.precompile += %w( administration.css )

Like most features in Rails, the usage of the Asset Pipeline is completely optional. To include assets in your project as it was done in Rails 3.0, set config.assets.enabled to false.

1.5.2 Asset Hosts

By default, Rails links to assets on the current host in the public folder, but you can direct Rails to link to assets from a dedicated asset server. The config.action_controller.asset_host setting is covered in detail in Chapter 11, “All About Helpers” in the “Using Asset Hosts” section.

1.6 Configuring a Database

The file database.yml found in the config folder specifies all the configuration settings required by Active Record to connect to a database. When a new application is generated, automatically generates sections for each environment.

The following is an example of a generated database.yml file configured to work with PostgreSQL.

1 # config/database.yml

2 default: &default

3 adapter: postgresql

4 encoding: unicode

5 # For details on connection pooling, see rails configuration guide

6 # http://guides.rubyonrails.org/configuring.html#database-pooling

7 pool: 5

8 username: example

9 password:

10

11 development:

12 <<: *default

13 database: example_development

14

15 # Connect on a TCP socket. Omitted by default since the client uses a

16 # domain socket that doesn't need configuration. Windows does not have

17 # domain sockets, so uncomment these lines.

18 #host: localhost

19

20 # The TCP port the server listens on. Defaults to 5432.

21 # If your server runs on a different port number, change accordingly.

22 #port: 5432

23

24 # Schema search path. The server defaults to $user,public

25 #schema_search_path: myapp,sharedapp,public

26

27 # Minimum log levels, in increasing order:

28 # debug5, debug4, debug3, debug2, debug1,

29 # log, notice, warning, error, fatal, and panic

30 # Defaults to warning.

31 #min_messages: notice

32

33 # Warning: The database defined as "test" will be erased and

34 # re-generated from your development database when you run "rake".

35 # Do not set this db to the same as development or production.

36 test:

37 <<: *default

38 database: example_test

39

40 production:

41 <<: *default

42 database: example_production

A common best practice within the Rails community has been not to store config/database.yml in version control. First and foremost, if a hacker gained access to the application repository, they would have all the connection settings to your production database. Secondly, developers on the team could potentially have different development and test database settings. New to Rails 4.1 is the ability to configure Active Record with an environment variable DATABASE_URL. This allows each developer working on the project to have their own copy of config/database.yml that is not stored in version control. The production environment of the Rails application would just need to have DATABASE_URL set with a valid connection string to be configured correctly.

1.7 Configuring Application Secrets

Being introduced in Rails 4.1 is the secrets.yml file found within the config folder. This file is meant to store your application’s sensitive data, such as access keys and passwords that are required for external APIs. At a minimum, Rails requires that secret_key_base is set for each environment of your application. In Rails 4.0, secret_key_base was set in the secret_token.rb initializer.

1 # config/secrets.yml

2

3 # Be sure to restart your server when you modify this file.

4

5 # Your secret key is used for verifying the integrity of signed cookies.

6 # If you change this key, all old signed cookies will become invalid!

7

8 # Make sure the secret is at least 30 characters and all random,

9 # no regular words or you'll be exposed to dictionary attacks.

10 # You can use `rake secret` to generate a secure secret key.

11

12 # Make sure the secrets in this file are kept private

13 # if you're sharing your code publicly.

14

15 development:

16 secret_key_base: 7aed4bcb28...

17

18 test:

19 secret_key_base: a4b717a2a8...

20

21 production:

22 secret_key_base: 39a63892bd...

warning

Kevin says….

I would strongly advice to not store any production secret values in version control. Like database.yml, if a hacker gained access to the application repository, they could use these values to exploit your application. Instead, set all production secret values to environment variables. The environment variables will only be set on your production machine.

# config/secrets.yml

...

production:

secret_key_base: <%= ENV['SECRET_KEY_BASE'] %>

A hash of all the secrets defined in config/secrets.yml can be accessed via Rails.application.secrets.

>> Rails.application.secrets

=> {:secret_key_base=>"7aed4bcb28..."}

To access a specific secrets, pass X to

An accessor for each secret key is also provided. For example, to access the secret for secret_key_base, invoke Rails.application.secrets.secret_key_base. This will return the value of secret_key_base for the current environment.

>> Rails.env

=> "development"

>> Rails.application.secrets.secret_key_base

=> "7aed4bcb28..."

Secret Token

Certain types of hacking involve modifying the contents of cookies without the server knowing about it. By digitally signing all cookies sent to the browser, Rails can detect whether they were tampered with. Rails signs cookies using the value of secret_key_base, found in config/secrets.yml, which is randomly generated along with your app.

1.8 Logging

Most programming contexts in Rails (models, controllers, view templates) have a logger attribute, which holds a reference to a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class. Can’t get a reference to logger somewhere in your code? The Rails.loggermethod references a logger that you can use anywhere.

It’s really easy to create a new Logger in Ruby, as shown in the following example:

1 $ pry

2 > require 'logger'

3 => true

4

5 > logger = Logger.new STDOUT

6 => #<Logger:0x00000106c795f0 @progname=nil, @level=0, ...>

7

8 > logger.warn "do not want!!!"

9 W, [2013-11-02T18:34:30.281003 #54844] WARN -- : do not want!!!

10 => true

11

12 > logger.info "in your logger, giving info"

13 I, [2013-11-02T18:34:57.186636 #54844] INFO -- : in your logger, giving info

14 => true

Typically, you add a message to the log using the logger whenever the need arises, using a method corresponding to the severity of the log message. The standard logger’s severities are (in increasingly severe order):

debug

Use the debug level to capture data and application state useful for debugging problems later on. This level is not usually captured in production logs.

info

Use info level to capture informational messages. I like to use this log level for time-stamping non-ordinary events that are still within the bounds of good application behavior.

warn

Use the warn level to capture things that are out of the ordinary and might be worth investigating. Sometimes I’ll throw in a logged warning when guard clauses in my code keep a client from doing something they weren’t supposed to do. My goal is to alert whoever’s maintaining the application about a malicious user or bug in the user interface, as in the following example:

1 def create

2 begin

3 group.add_member(current_user)

4 flash[:notice] = "Successfully joined #{scene.display_name}"

5 rescue ActiveRecord::RecordInvalid

6 flash[:error] = "You are already a member of #{group.name}"

7 logger.warn "A user tried to join a group twice. UI should

8 not have allowed it."

9 end

10

11 redirect_to :back

12 end

error

Use the error log level to capture information about error conditions that don’t require a server restart.

fatal

The worst-case imaginable has happened—your application is now dead and manual intervention is necessary to restart it.

1.8.1 Rails Log Files

The log folder of your Rails application holds three log files corresponding to each of the standard environments. Log files can grow very large over time. A rake task is provided for easily clearing the log files:

$ rake log:clear # Truncates all *.log files in log/ to zero bytes

The contents of log/development.log are very useful while you’re working. Many Rails coders leave a terminal window open with a continuous tail of the development log open while they’re coding:

$ tail -f log/development.log

Article Load (0.2ms) SELECT "articles".* FROM "articles" WHERE

"articles"."id" = $1 LIMIT 1 [["id", "1"]]

All sorts of valuable information are available in the development log. For instance, every time you make a request, a bunch of useful information about it shows up in the log. Here’s a sample from one of my projects.

1 Started GET "/user_photos/1" for 127.0.0.1 at 2007-06-06 17:43:13

2 Processing by UserPhotosController#show as HTML

3 Parameters: {"/users/8-Obie-Fernandez/photos/406"=>nil,

4 "action"=>"show", "id"=>"406", "controller"=>"user_photos",

5 "user_id"=>"8-Obie-Fernandez"}

6 User Load (0.4ms) SELECT * FROM users WHERE (users.'id' = 8)

7 Photo Load (0.9ms) SELECT * FROM photos WHERE (photos.'id' = 406

8 AND (photos.resource_id = 8 AND photos.resource_type = 'User'))

9 CACHE (0.0ms) SELECT * FROM users WHERE (users.'id' = 8)

10 Rendered adsense/_medium_rectangle (1.5ms)

11 User Load (0.5ms) SELECT * FROM users WHERE (users.'id' = 8)

12 LIMIT 1

13 SQL (0.4ms) SELECT count(*) AS count_all FROM messages WHERE

14 (messages.receiver_id = 8 AND (messages.'read' = 0))

15 Rendered layouts/_header (25.3ms)

16 Rendered adsense/_leaderboard (0.4ms)

17 Rendered layouts/_footer (0.8ms)

18 Rendered photos/show.html.erb within layouts/application.html.erb (38.9ms)

19 Completed in 99ms (Views: 37.4ms | ActiveRecord: 12.3ms) with 200

This is a list of all the data items contained in that chunk of log output:

· The controller and action that were invoked

· The remote IP address of the computer making the request

· A timestamp indicating when the request happened

· The session ID associated with the request

· The hash of parameters associated with the request

· Database request information including the time and the SQL statement executed

· Query cache hit info including time and the SQL statement triggering results from the cache instead of a roundtrip to the database

· Rendering information for each template involved in rendering the view output and time consumed by each

· Total time used in completing the request with corresponding request-per-second figures

· Analysis of the time spent in database operations versus rendering

· The HTTP status code and URL of the response sent back to the client

1.8.2 Tagged Logging

Log files can contain an extensive amounts of information, making tracking down issues or particular requests difficult. To alleviate this issue, Rails 3.2 introduced the ability to prepend information to each of your log messages.

To add “tagged” information to your logs, pass an array of one or many method names which respond to the request object to the config.log_tags configuration setting.

To illustrate, assuming we want to track the subdomain that each request is made from, we can achieve this by setting config.log_tags to [:subdomain]. When Rails writes to the log, it will prefix the output of request.subdomain, resulting in a log message like the following:

[some_subdomain] Started GET "/articles" for 127.0.0.1 at 2013-02-01 11:49:09 -0500

1.8.3 Log File Analysis

A number of informal analyses can be easily performed using just the development log output and some common sense.

Performance

One of the more obvious analyses would be a study of the performance of your application. The faster your requests execute, the more requests you can serve with a given Rails process. That’s why performance figures are often expressed in terms of requests per second. Find the queries and rendering sections that are taking a long time and figure out why.

It’s important to realize that the times reported by the logger are not super-accurate. In fact, they’re wrong more often than not, if simply for the reason that it’s very difficult to measure the timing of something from within itself. Add up the percentage of rendering and database times for any given request and it will not always be close to 100%.

However, despite not being accurate in a purely objective sense, the reported times are perfect for making subjective comparisons within the same application. They give you a way of gauging whether an action is taking longer than it used to, or whether it is relatively faster or slower than another action, and so on.

SQL queries

Active Record not behaving as expected? The fact that SQL generated by Active Record is logged can often help you debug problems caused by complicated queries.

Identification of N+1 select problems

Whenever you are displaying a record along with an associated collection of records, there’s a chance that you will have a so-called N+1 select problem. You’ll recognize the problem by a series of many SELECT statements, with the only difference being the value of the primary key.

For example, here’s a snippet of some log output from a real Rails application showing an N+1 select issue in the way that FlickrPhoto instances are being loaded:

1 FlickrPhoto Load (1.3ms) SELECT * FROM flickr_photos WHERE

2 (flickr_photos.resource_id = 15749 AND flickr_photos.resource_type =

3 'Place' AND (flickr_photos.'profile' = 1)) ORDER BY updated_at desc

4 LIMIT 1

5 FlickrPhoto Load (1.7ms) SELECT * FROM flickr_photos WHERE

6 (flickr_photos.resource_id = 15785 AND flickr_photos.resource_type =

7 'Place' AND (flickr_photos.'profile' = 1)) ORDER BY updated_at desc

8 LIMIT 1

9 FlickrPhoto Load (1.4ms) SELECT * FROM flickr_photos WHERE

10 (flickr_photos.resource_id = 15831 AND flickr_photos.resource_type =

11 'Place' AND (flickr_photos.'profile' = 1)) ORDER BY updated_at desc

12 LIMIT 1

and so on and so forth, for pages and pages of log output. Look familiar?

Luckily, each of those database queries is executing very quickly, around 0.0015 seconds each. That’s because 1) MySQL is extraordinarily fast for small SELECT statements and 2) my Rails process is on the same physical machine as the database.

Still, accumulate enough of those N queries and they add up quickly to eat away at performance. Absent the mitigating factors I mentioned, I would have a serious performance problem to address. The problem would be especially severe if the database was on a separate machine, giving me network latency to deal with on each of those queries.

N+1 select issues are not the end of the world. A lot of times all it takes is proper use of the includes method on a particular query to alleviate the problem.

information

Separation of Concerns

A well-designed model-view-controller application follows certain protocols related to which logical tier does database operations (that would be the model) versus rendering tasks (the view). Generally speaking, you want your controller to cause the loading of all of the data that is going to be needed for rendering from the database. In Rails, it is accomplished by controller code that queries the model for needed data and makes that data available to the view.

Database access during rendering is usually considered a bad practice. Calling database methods directly from template code violates proper separation of concerns and is a maintainability nightmare.5

However, there are plenty of opportunities for implicit database access during view rendering to creep into your codebase, encapsulated by the model, and perhaps triggered by lazy loading of associations. Can we conclusively call it a bad practice? It’s hard to say so definitively. There are cases (such as usage of fragment caching) where it makes sense to have database operations happening during view rendering.

information

Using Alternate Logging Schemes

It’s easy! Just assign a class compatible with Ruby’s Logger to one of the various logger class variables, such as ActiveRecord::Base.logger. A quick hack based on the ability to swap loggers is one demonstrated by David at various events, including his keynote at Railsconf 2007. During a console session, assign a new Logger instance pointing to STDOUT toActiveRecord::Base.logger in order to see the SQL being generated right in your console. Jamis has a complete write-up of the technique and more at http://weblog.jamisbuck.org/2007/1/31/more-on-watching-activerecord.

1.8.3.1 Rails::Subscriber.colorize_logging

Tells Rails whether to use ANSI codes to colorize the logging statements. The colors make it much easier to read the logs (except on Windows) and may complicate matters if you use software like syslog. Defaults to true. Change to false if you view your logs with software that doesn’t understand the ANSI color codes.

Here’s a snippet of log output with the ANSI codes visible:

1 ^[[4;36;1mSQL (0.0ms)^[[0m ^[[0;1mMysql::Error: Unknown table

2 'expense_reports': DROP TABLE expense_reports^[[0m

3 ^[[4;35;1mSQL (3.2ms)^[[0m ^[[0mCREATE TABLE expense_reports ('id'

4 int(11) DEFAULT NULL auto_increment PRIMARY KEY, 'user_id' int(11))

discussion

Wilson says…

Almost nobody I meet seems to know how to display colorized logs in a pager. The -R option tells less to output “raw” control characters to the screen.

information

Syslog

UNIX-like systems have a system service called syslog. For various reasons, it might be a better choice for production logging of your Rails applications.

· Finer-grained control over logging levels and content.

· Consolidation of logger output for multiple Rails applications.

· If you’re using remote syslog capabilities of many systems, consolidation of logger output for multiple Rails application servers is possible. Contrast with having to handle individual log files on each application server box separately.

You can use Eric Hodel’s SyslogLogger to interface your Rails application to syslog.

1.8.4 Conclusion

We’ve kicked off our Rails journey by covering Bundler in fairly good detail and then reviewing the different environments in which Rails executes and how it loads its dependencies, including your application code. An in-depth look at config/application.rb and its per-mode variants revealed how we can customize Rails behavior to our taste.