Rails routing: Using constraints to avoid "Missing template" errors
You can use constraints in your routes.rb to avoid getting ActionView::MissingTemplate errors when wrong routes are called. Instead, the user will see a 404.
If you want multiple routes to use the same constraint you can use the block syntax:
constraints(format: 'html') do
resources :pages
resources :images
end
If you want constraints only on certain routes, you can do:
get '/users/account' => 'users#account', constraints: { format: 'html' }
Tip
You can also avoid this error type through [format con...
Capistrano + Rails: Tagging production deploys
Just like Ruby Gems tag their version releases to the corresponding Git commit, it can be helpful to track production deploys within the commit history. This task does the tagging for you.
Capistrano 3
# lib/capistrano/tasks/deploy.rb
namespace :deploy do
...
desc 'Tag the deployed revision'
task :tag_revision do
date = Date.today.to_s
puts `git tag deploy-#{date} #{fetch :current_revision}`
puts `git push --tags origin`
end
end
# config/deploy/production.rb
after 'deploy:finished', 'deploy:tag_...
Supporting multiple SAML IdPs within a single Rails application
The linked article shows how to configure omniauth-multi-provider to support multiple SAML identity providers for a single Rails app:
To solve this, the omniauth-multi-provider gem acts as a dynamic wrapper around OmniAuth. It enables your application to load the correct IdP configuration at runtime—based on the tenant—allowing for flexible and secure SSO authentication across multiple organisations.
bower-rails can rewrite your relative asset paths
The asset pipeline changes the paths of CSS files during precompilation. This opens a world of pain when CSS files reference images (like jQuery UI) or fonts (like webfont kits from Font Squirrel), since all those url(images/icon.png) will now point to a broken path.
In the past we have been using the vendor/asset-libs folder ...
Rails: Using database default values for boolean attributes
In the past we validate and set default values for boolean attributes in Rails and not the database itself.
Reasons for this:
- Older Rails didn't support database defaults when creating new records
- Application logic is "hidden" in the database
An alternative approach, which currently reflects more the general opinion of the Rails upstream on constraints in the database, is adding default values in the schema of the database itself. We also ...
Rails: Migration helper for inserting records without using models
You should avoid using application models in your migrations. But how else could you create records in a migration?
The most basic way is to write plain SQL, but since INSERT statements are no pleasant write for Rubyists, here is a simple wrapper:
Record creation helper for migrations
The helper method below takes a table name and a hash of attributes, which it inserts into the specified table. Copy it over to your migration and profit!
private
def insert_record(table, **attributes)
attributes.merge!...
Rails: Integrating shoelace components
shoelace is a library of web components. Here is a proof of concept how a integration (slightly different as the official docs for Rails) might look like in Rails + webpack + Unpoly. Also see the HN discussion for pro and cons.
Solving "TypeError (nil can't be coerced into Integer)" in the Rails console / IRB
On the Rails console, assigning an object to a variable can lead to this strange error (without stacktrace):
irb > recipient = Recipient.find(123)
Traceback (most recent call last):
TypeError (nil can't be coerced into Integer)
irb > recipient
#<Recipient ...
The error is only in the output – the assignment is working. It only occurs when using the --nomultiline option, and thus [only with IRB 1.2.0+ and before Ruby 3](https://github.com/makandra/geordi/blob...
Rails < 5: How to get after_commit callbacks fired in tests
If you use transactional_fixtures or the database_cleaner gem with strategy :transaction, after_commit callbacks will not be fired in your tests.
Rails 5+
Rails 5 has a fix for this issue and no further action is needed.
Rails 3, Rails 4
Add the gem test_after_commit to your test group in the Gemfile and you are done. You don't need to change the database strategy to deletion (wh...
Ruby: How to measure code execution time in an IRB or Rails console
Modern IRB has time measurement built in.
measure # Enable
measure :off # Disable
Custom
Should your version of IRB not offer this feature, you can measure manually. Paste this method into your console:
def time(&block) puts Benchmark.measure(&block) end
Now time { Some.lengthy_task } will behave similar to the bash time command. Of course you can do much more with the Benchmark object than just putsing it – adapt to your needs.
Rails: render a template that accepts a block by using the layout option of render
Let's say you have a form that you render a few times but you would like to customize your submit section each time. You can achieve this by rendering your form partial as layout and passing in a block. Your template or partial then serves as the surrounding layout of the block that you pass in. You can then yield back the form to the block and access the form in your block.
-# record/_form.haml
= form_for record do |form|
-# ...
.form-actions
yield(form)
In order to make your template record/_form.haml accept a...
Why Sidekiq Jobs should never be enqueued in an `after_create` or `after_save` callback
When an object is created / updated, various callbacks are executed in this order:
before_validation
after_validation
before_save
around_save
before_create
around_create
after_create
after_save
after_commit / after_rollback
Thus, each of these callbacks is executed at a specific time in the life cycle of the object. This is important because this point in time determ...
Rails: Removing the cucumber-rails warning when setting cache_classes to false without Spring enabled
We are using Spring in our tests for sequential test execution but not for parallel test execution. And Rails requires you to set the config.cache_classes = false if you are using Spring in tests.
With our setup, this would raise the following error in cucumber-rails for parallel test executions due to some legacy database cleaner issue.
WARNING: You have set Rails' config.cache_classes to false
(Spring needs cache_classes set to false). This is known to cause probl...
whenever: Installing cron jobs only for a given Rails environment or Capistrano stage
We use the whenever gem to automatically update the crontab of the servers we deploy to. By default, whenever will update all servers with a matching role (we use the :cron role ).
This card describes how to install some tasks only for a given Rails environment or for a given Capistrano stage ("deployment target").
Installing jobs only for a given Rails environment
-----------------------------------...
Debug MiniMagick calls in your Rails app
Most of our applications use CarrierWave for file uploads. CarrierWave has an integrated processing mechanism for different file versions with support for ImageMagick through CarrierWave::MiniMagick (which requires the mini_magick gem). In case your processing runs into an error, CarrierWave will just swallow it and rethrow an error with a very generic message like Processing failed. Maybe it is not an image? which does not help you finding out what the actual problem is. CarrierWave probably does this for security purposes, but does n...
Rails migration: Changing a column type without losing the content
The change_column method for rails migrations support casting with a custom SQL statement. This allows us to change a column type and keep the former content as the new type. This way, we can for example prepare an address number column to hold German address numbers, which can contain letters:
Example (in most cases not a good idea!)
class ChangeAnIntegerColumnToString < ActiveRecord::Migration[6.1]
def up
change_column :users, :address_number, 'varchar USING CAST(rating AS varchar)'
end
def down
change_column ...
How to use Rails URL helpers in any Ruby class
If you have any class which requires access to some path methods generated by your routes. Even though you could technically include Rails.application.routes.url_helpers, this may include way too many methods and even overwrite some class methods in the worst case.
Instead, most of the time the following is advised to only make the desired methods available:
class Project
delegate :url_helpers, to: 'Rails.application.routes'
def project_path
url_helpers.project_path(self)
end
end
Rails: Rescuing exceptions for specific exception types
By default most exceptions in Rails will render a 500 error page and will create a new issue in your error monitoring. There are some built-in rules in Rails that
- render a different error than 500
- will rescue the exception and not create an issue in your error monitoring
A good example is ActiveRecord::NotFound: You don't want an exception in your error monitoring when users navigate to e.g. a blog post t...
Howto respond html or json in the same controller action with Rails 2
Code snippet tested with Rails 2.3
def index
# ...
if request.xhr?
html = render_to_string(:partial => "list", :layout => false)
respond_to do |format|
format.html { render :text => html }
format.json { render :json => {:html => html, ... } }
end
end
end
Note: Perhaps you ran into ActionView::MissingTemplate error and this card might help. If you call render_to_string within the format.json block, Rails will only look for an index.json template, but not for an `index.erb...
Middleman configuration for Rails Developers
Middleman is a static page generator that brings many of the goodies that Rails developers are used to.
Out of the box, Middleman brings Haml, Sass, helpers etc. However, it can be configured to do even better. This card is a list of improvement hints for a Rails developer.
Gemfile
Remove tzinfo-data and wdm unless you're on Windows. Add these gems:
gem 'middleman-livereload'
gem 'middleman-sprockets' # Asset pipeline!
gem 'bootstrap-sass' # If you want to use Bootstrap
gem 'byebug'
gem 'capistrano'
gem 'capistrano-mid...
Security issues with hash conditions in Rails 2 and Rails 3
Find conditions for scopes can be given either as an array (:conditions => ['state = ?', 'draft']) or a hash (:conditions => { 'state' => 'draft' }). The later is nicer to read, but has horrible security implications in some versions of Ruby on Rails.
Affected versions
| Version | Affected? | Remedy |
|---|---|---|
| 2.3.18 | yes | Use chain_safely workaround |
| 3.0.20 | no | ... |
How to debug issues with zeitwerk and Rails
In case you have trouble with the zeitwerk autoloader, you can check out the documentation Autoloading and Reloading Constants and Classic to Zeitwerk HOWTO for some debugging hints.
For myself it was useful to print the registered constants and the file references during the boot. Therefore you need to add Rails.autoloaders.log! at the end of your config/application.rb file. You could also run `bin...
Rails: When defining scopes with class methods, don't use `self`
Sometimes it is useful to define a named scope by implementing a static method with the scope's name on the scoped class. For instance, when a method should decide which existing scope should be the next link in the scope chain. Take this class for example:
class Meal < ActiveRecord::Base
named_scope :for_date, lambda { |date| :conditions => { :date => date }}
named_scope :with_meat, :conditions => { :meat => true }
named_scope :without_meat, :conditions => { :meat => false }
def self.suitable_for(user)
if user.vegetar...
Rails: Validations of Dates, Numerics and Strings with ComparisonValidator
tl;dr
Since Rails
7+you can useComparisonValidatorfor validations likegreater_than,less_than, etc. on dates, numerics or strings.
Example
We have a model for booking a trip. This model has mandatory attributes to enforce dates for the start and the end.
# == Schema Information
#
# start_date :date
# end_date :date
# ...
class TripBooking < ApplicationRecord
validates :start_date, presence: true
validates :end_date, presence: true
end
These validations are enough. We also want to ensure, th...