Tag: routing error

Upgrading to Rails 4.0 from Rails 3.2 – Test case – Part I (preparations, configuration, gems)

In this articles series, I'll try to cover all the issues that I had, when I was upgrading one of my Rails app from Ruby on Rails 3.2 to Ruby on Rails 4.0.

Preparations - What should we do before upgrading to Rails 4?

  • Upgrade your Ruby version at least to 1.9.3 (I would recommend 2.0)
  • Upgrade bundler
  • Upgrade your application to the most recent Rails 3.2 version
  • Check gems compatibility (you may want to be on edge with few gems (or use Rails 4 branches))
  • Write more tests if you don't have a decent code coverage

The last point is the most important. If you don't have a good code coverage level and you lack tests, upgrading from Rails 3.2 to Rails 4 might be a big problem.

Attributes protected and some other Rails 3 features

Rails team moved a lot of stuff from Rails core to gems. In order to make an upgrade smooth, probably the best solution is to add all the gems into Gemfile and then upgrade given functionalities one by one after successful Rails 4 migration:

gem 'protected_attributes' # https://github.com/rails/protected_attributes
gem 'active_resource' # https://github.com/rails/activeresource
gem 'actionpack-action_caching' # https://github.com/rails/actionpack-action_caching
gem 'activerecord-session_store' # https://github.com/rails/activerecord-session_store
gem 'rails-observers' # https://github.com/rails/rails-observers
# Note that there might be more functionalities that were extracted

Be aware, that some of those gems might not be maintained longer than till Rails 4.1 release!

Upgrading to Rails 4 - Gemfile

First thing that needs to be done, when upgrading to Rails 4 is changing our Gemfile:

gem "rails", '~>4.0.0'
# Remember to require dalli if you're using memcached
gem 'dalli'
# Remember to update any gems that require something special in order to work with Rails 4
gem 'squeel', :git => "git://github.com/ernie/squeel.git"
gem "ransack", :git => "git://github.com/ernie/ransack.git", :branch => 'rails-4'
gem 'simple_form', :git => 'git://github.com/plataformatec/simple_form.git'

Also if you have an assets group, it needs to be removed. You can move the assets gems to a default group:

# group :assets <--- this needs to go away
gem 'coffee-rails'
gem 'sass-rails'
gem 'uglifier'
# end

After updating your Gemfile you can do a

bundle install

and hopefully you're ready for upgrade!

Configuration files - rake rails:update

There are some changes in configuration files (that I will cover), but I would strongly recommend running:

rake rails:update

allow it to overwrite your files and then just add the stuff that you've needed and is not there. IMHO it is way less complex approach, that trying to add all new config options manually.

Rails.root + /config/environments/*.rb

Things that are no longer available and need to be removed from those file:

  • config.whiny_nils = true
  • config.action_dispatch.best_standards_support = :builtin
  • config.active_record.mass_assignment_sanitizer = :strict
  • config.active_record.auto_explain_threshold_in_seconds = 0.5

Things that need to be added (with values appropriate for given environment):

  • config.eager_load = false
  • config.active_record.migration_error = :page_load

Things that need to be changed:

  • config.cache_store = :dalli_store => config.cache_store = :mem_cache_store

Remember to set eager_load in all environments. If not, you'll see following warning:

config.eager_load is set to nil. Please update your config/environments/*.rb files accordingly:

  * development - set it to false
  * test - set it to false (unless you use a tool that preloads your test environment)
  * production - set it to true

If you don't remove the auto_explain_threshold_in_second option, you'll see following warning:

DEPRECATION WARNING: The Active Record auto explain feature has been removed.

To disable this message remove the `active_record.auto_explain_threshold_in_seconds`
option from the `config/environments/*.rb` config file.


In Rails 3 filter_parameters setting was set up in application.rb. In Rails 4 there will be created an initializer for that (config/initializers/filter_parameters.rb):

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

So you may consider moving this setting our of your application.rb file.

Secret token (config/initializers/secret_token.rb)

There is a new value for that initializer:

Susanoo::Application.config.secret_token = 'your current token'
Susanoo::Application.config.secret_key_base = 'secret value' # this needs to be added

The secret_key_base is not required but if you don't add it, you'll have a deprecation warning:

DEPRECATION WARNING: You didn't set config.secret_key_base.

Cookies from Rails 3 will be transformed automatically into Rails 4 format but be aware, that this won't work the other way around, so if by any reason you'll want to get back to Rails 3, all the user cookies will be unreadable.

In order to generate a random secret_key value, you can use rake task:

rake secret

This will just generate secret, you need to copy it to this initializer manually!

Rails.root + /config/application.rb

If you had any interactions with routes loading process you need to change config/routes in such a way:

config.paths['config/routes.rb'] # add .rb


# Load all the routes from routes directory
Dir["#{Rails.root}/config/routes/**/*.rb"].each do |route_file|
  config.paths['config/routes.rb'] << route_file


If you have a decent code coverage level and you know what you're doing, upgrade should not be a big problem. At this point, if you're not using any fancy route settings, you should be able to at least start your application:

./script/rails s -u

I'll cover more deprecation warnings and other issues soon.

Rails routes: limiting access to application parts from certain domains (hosts)

Sometimes we want to handle different parts of a single application from different domains. A good example of such an approach is when we have a scope containing our API. Wouldn't it be great if it could be served from a different domain than the rest of the application? Of course yes! Approach like this (separating the API from the rest of the app) is used in several popular web applications. For example in Twitter. The app is under twitter.com and the API lies under the api.twitter.com url. When you have a smaller Rails app, probably you maintain the API-part and the user-part in one Rails project. The separate domains approach allows you to easily move to the two different apps, when the time comes.

So, how to limit access to the app parts based on the domain? Let's use constraints. Let's assume, that we have a scope called :api and the scope called :ui. Each scope represents a module in our app:

scope :module => :api do
  # Some resources and additional routes here
  # Api::SomeController...

scope :module => :ui do
  # Some resources and additional routes here
  # Ui::SomeController...

To make it domain-accessible we just need to wrap it with a block like this one:

constraints(:host => 'my_domain') do
# Routes here

where the my_domain is a domain that should be used with our app part. So for the example above, it would look like this:

constraints(:host => 'api.example.com') do
  scope :module => :api do
    # Some resources and additional routes here
    # Api::SomeController...

constraints(:host => 'my.app.example.com') do
  scope :module => :ui do
    # Some resources and additional routes here
    # Ui::SomeController...

Copyright © 2024 Closer to Code

Theme by Anders NorenUp ↑