Running Rails 2 apps with modern MariaDB SQL server

You might have some trouble running a Rails LTS 2 app with MySQL 5.7.

If you don't want to hack Mysql 5.6 into your modern Ubuntu or use the MySQL sandbox, you might want to try MariaDB 10.x.

MariaDB 10.x should work with both old and new Rails applications.

[Switch to MariaDB](https://makandracards.com/makandra/468343-how-...

Rails routes: Extracting collection actions into their own controllers

Let's say you have two screens:

  1. Show a given project
  2. Show a report for all projects

Ideally you want both screens to be handled by different controllers like this:

GET /projects/:id        => ProjectsController#show
GET /projects/report     => Projects::ReportsController#show

What seems like a simple requirement is a little awkward to configure in your routes.
Obviously the report should be a singleton resource, but how can we nest it into the Projects:: namespace?

What does not work is this:

resources :proj...

Rails: How to use custom flash types in controllers

Rails supports alert and notice as default flash types. This allows you to use these keys as options in e.g. redirect_to and as a helper in views e.g. <%= notice %> (instead of flash[:notice]).

class SomeController < ApplicationRecord
  def create
    @user = User.create!
    
    redirect_to user_path(@user), notice: "#{@user} created!" 
  end
end

In case you are using Bootstrap as CSS framework you might also want to support flashes like success. This can be done with the add_flash_types method.

class Applicat...

How Rails and MySQL are handling time zones

When working with times and dates in Rails applications, you need to deal with the following problem:

  • In Rails, Time objects have a time zone. You can get the zone name by doing time_object.zone.
  • This zone is considered when doing time calculations, e.g. 10 AM CEST minus 8 AM UTC is zero.
  • A datetime in MySQL does not have a zone. It just stores the literal string "2010-05-01 12:00:00".
  • That means that Rails must make assumptions about timestamps loaded from and written to MySQL.

Rails has two completely different modes ...

Embed Google Analytics code for some environments only

When you use google analytics to track your visitors interactions, you should ensure that it runs on your production site only. Otherwise it will spoil your statistics. To prevent this, test for the right environment and place the JS-code afterwards:

- if Rails.env.production?
  :javascript
    var _gaq = _gaq || [];
    _gaq.push(['_setAccount', 'UA-XXXXXXXX-X']);
    _gaq.push(['_trackPageview']);
    ...

Fix error: can’t find executable rails

If you get an error like this ...

 can’t find executable rails for rails-3.2.3 (Gem::Exception)

... one of several things might be wrong.

  1. You're using RVM

It's possible that you have a system-wide gem executable (like rails) that requires a gem that is not available in the current RVM Ruby or gemset. Check what Ruby you are using (rvm current) and look out for .rvmrc files in your current directory (which change your Ruby upon entering the directory).

  1. You killed a gem install process
    ----------...

Rails 3: Mass assignment protection and .create_with

The issue

Yesterday, Rails fixed a security issue (CVE-2014-3514) in Rails 4+. It was possible to use .where or .create_with to bypass Rails' Strong Parameters:

user.blog_posts.create_with(params[:blog_post]).create

would set all attributes on the blog post. After the fix, you have to properly whitelist the params, via `params[:blog_post].permit(:title, :bo...

Rails: Verify the CSRF token

Rails uses a CSRF token in forms and AJAX requests to verify a user request. Internally it compares the injected CSRF token of the form data with the CSRF token in the encrypted user session. To prevent SSL BREACH attacks, the CSRF token from the form data is masked.

To better debug issues, when these tokens do not match, it is useful to unmask the CSRF token from the form da...

Rails 2's CookieStore produces invalid cookie data, causing tests to break

Note that this seems to affect only recent Rails 2 versions.

You will not encounter this until you are writing to the cookie more than once, but when doing so, integration tests (Cucumber) may break for you with this error:

You have a nil object when you didn't expect it!
You might have expected an instance of ActiveRecord::Base.
The error occurred while evaluating nil.[] (NoMethodError)

Background

The regular/short cucumber backtrace is not of any help but looking at the full trace reveals that ActionPack's `actio...

Comparing Rails' flash hashes will not respect their internal lists of used entries

Rails flashes (FlashHash) track a list of used keys, which is not respected when comparing flash hashes.

This does not concern you under most circumstances.

Basics

When ActionController picks up a flash object, it will call the #sweep method once; that method checks the list of used flash entries and deletes those. All other entries are flagged as used. This means they will be deleted on the next request, but are still be available for rendering during the current request.

Fun facts: When redirecting, this does not happen. Also,...

How to avoid ActiveRecord::EnvironmentMismatchError on "rails db:drop"

After loading a staging dump into development, you might get an ActiveRecord::EnvironmentMismatchError when trying to replace the database (like rails db:drop, rails db:schema:load).

$ rails db:drop
rails aborted!
ActiveRecord::EnvironmentMismatchError: You are attempting to modify a database that was last run in `staging` environment.
You are running in `development` environment. If you are sure you want to continue, first set the environment using:

        bin/rails db:environment:set RAILS_ENV=development

Starting with R...

passenger problems with upgraded rails-app

You may encounter problems with passenger starting an application with an updated rails.
If you find an error like this in the apache error log:

[ 2015-08-21 10:53:04.1266 17680/7f4909bf7700 Pool2/Implementation.cpp:883 ]: Could not spawn process for group /var/www/example.com/current#default: An error occured while starting up the preloader.
     in 'void Passenger::ApplicationPool2::SmartSpawner::handleErrorResponse(Passenger::ApplicationPool2::SmartSpawner::StartupDetails&)' (SmartSpawner.h:455)
     in 'std::string Passenger::Appli...

Rails: Concurrent requests in development and tests

With puma you can have concurrent requests. There are two concepts on how Puma can handle two incoming requests: Workers and Threads.

Workers

Puma can have multiple workers. Each worker is a process fork from puma and therefore a very heavy instance and can have multiple threads, that handle the incoming requests.

Example: A Puma server with 2 workers and 1 thread each can handle 2 request in parallel. A third request has to wait until the thread of one of the workers is free.

Threads

Rails is thread-safe since version 4 (n...

Rails: How to restore a postgres dump from the past

It sometimes happen that a database dump, that would want to insert into your development database, does not match the current schema of the database. This often happens when you have an old dump, but your current setup is up to date with the the master.

Hint: In most cases it is sufficient to delete and recreate the local database in order to import the dump. If any problems occur, proceed as follows:

1. Figure out the original migration status of the dumpfile

  • Convert your dump to plaintext: `pg_restore -f some.dump > some.dump....

Sharing cookies across subdomains with Rails 3

To achieve this goal you have to setup the session store like the following example:

  MyApp::Application.config.session_store(
    :cookie_store,
    {
      :key => '_myapp_session',
      :domain => :all, # :all defaults to da tld length of 1, '.web' has length of 1
      :tld_length => 2 # Top Level Domain (tld) length -> '*.myapp.web' has a length of 2
    }
  )

The invconvenient side effect for local development

… or: Why do I get "Can't verify CSRF token authenticity" even if csrf token is present?

As `:domain => :all...

Signed URLs with Ruby on Rails

Using ActiveRecord's #signed_id and .find_signed methods you can create URLs that expire after some time. No conditionals or additional database columns required.

Speed up file downloads with Rails, Apache and X-Sendfile

When you use the send_file method to send a local file to the browser, you can save resources on the application server by setting the :x_sendfile option to true. This option is activated by default for Rails 3, so you need to understand this.

What this option does is not to send any data at all, but rather set the local file path as a new response header:

X-Sendfile: /opt/www/awesome-project/shared/downloads/image.png

When the response comes back from Rails to...

Test a gem in multiple versions of Rails

Plugins (and gems) are typically tested using a complete sample rails application that lives in the spec folder of the plugin. If your gem is supposed to work with multiple versions of Rails, you might want to use to separate apps - one for each rails version.

For best practice examples that give you full coverage with minimal repitition of code, check out our gems has_defaults and assignable_values. In particular, take a look at:

  • Multiple `sp...

Rails 2: Refuse response formats application-wide

If you regularly get ActionView::MissingTemplate exceptions, maybe some bot visits your site requesting silly formats like:

http://www.rails-app.com/makandra.html-username-2000 # => Rails tries to retrieve 'makandra' with format 'html-username-2000'

Just restrict accepted format parameters for the whole application like this:

class ApplicationController < ActionController::Base

  before_filter :refuse_silly_formats

  private

  def refuse_silly_formats
    acceptable_formats = %w[html xml pdf]

    if par...

Beware of rails' reverse_order!

#reverse_order does not work with complex sorting constraints and may even silently create malformed SQL for rails < 5.

Take a look at this query which orders by the maximum of two columns:

Page.order('GREATEST(pages.published_from_de, pages.published_from_en) DESC').to_sql
# => SELECT "pages".* FROM "pages" ORDER BY GREATEST(pages.published_from_de, pages.published_from_en) DESC

Rails 4

Rails 4 will not immediately raise but creates malformed SQL when trying to use reverse_order on this query:

Pageorder('GRE...

Using Spring and parallel_tests in your Rails application

You want Spring for super-fast binstubs like bin/rails or bin/rspec which avoid Rails boot time.
You want parallel_tests to speed up full test runs of large test suites.

Unfortunately, you do not want parallel_tests to use your Spring binstubs as those parallelized tests will share data and/or loose some information. There are some issues about this on GitHub and there is a suggested [workaround](https:...