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...
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...
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...
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
-----------------------------------...
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 ...
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...
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
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 | ... |
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...
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...
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...
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...
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: 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...
How to kill a Rails development server by force
Sometimes, the rails dev server doesn't terminate properly. This can for example happen when the dev server runs in a RubyMine terminal.
When this happens, the old dev server blocks port 3000, so when you try to start a new server, you get the error:
Address already in use - bind(2) for "127.0.0.1" port 3000 (Errno::EADDRINUSE)
You can terminate such a dev server with this command:
lsof -t -i :3000 -s TCP:LISTEN | xargs kill -9
It might be worth it to add this to your bash aliases.
Rails: Custom validator for "only one of these" (XOR) presence validation
For Rails models where only one of multiple attributes may be filled out at the same time, there is no built-in validation.
I've seen different solutions in the wild, each with different downsides:
- Private method referenced via
validate: works, but is barely portable and clutters the model. - Multiple presence validations with "if other is blank" each: looks pretty, but is incorrect as it allows both values to be filled in; also the error messages for a blank record are misleading.
Here is a third option: Write a custom validator to ...
Rails: Testing the number of database queries
There are a few tools to combat the dreaded n+1 queries. The bullet gem notifies you of missing eager-loading, and also if there is too much eager-loading. strict_loading in Rails 6.1+ forces developers to explicitly load associations on individual records, for a single association, for an entire model, or globally for all models.
But you can also actually **write spe...
An incomplete guide to migrate a Rails application from paperclip to carrierwave
In this example we assume that not only the storage gem changes but also the file structure on disc.
A general approach
Part A: Create a commit which includes a script that allows you to copy the existing file to the new file structure.
Part B: Create a commit which removes all paperclip logic and replace it with the same code you used in the first commit
Part A
Here are some implementation details you might want to reuse:
- Use the existing models to read the files from
- Use your own carrierwave models to write t...
Rails: How to test the parsed response body
Testing your responses in Rails allows to parse the body depending on the response MIME type with parsed_body.
get '/posts.json'
response.parsed_body # => [{'id' => 42, 'title' => 'Title'}, ...]
For JSON APIs we often parse the response as symbolized keys with JSON.parse(response.body, symbolize_names: true), which is not supported by parsed_body. For all other cases you might want to drop JSON.parse(response.body) and replace it w...
Rails: Remove Blank Values from Collections
tl;dr
Since Rails
6.1+you can use.compact_blankor.compact_blank!to remove blank values from collections (e.g. arrays).
Remove nil values from an array
['foo', nil].compact
# => ['foo']
# You can use the splat operator to ignore nil values when constructing an array
['foo', *nil]
# => ['foo']
Remove blank values from collections
Array
array = [1, "", nil, 2, " ", [], {}, false, true]
# Any Rails version
array.reject(&:blank?)
# => [1, 2, true]
# Since Rails 6.1+
array.compact_blank
# ...
RSpec: how to prevent the Rails debug page if you want to actually test for 404s
Within development and test environments, Rails is usually configured to show a detailed debug page instead of 404s. However, there might be some cases where you expect a 404 and want to test for it.
An example would be request-specs that check authorization rules. (If you use a gem like consul for managing authorization rules, you should always check these rules via power-specs. However, request-specs can be used as a light-weight version of integration tests here.)
In this case, Rails will replace the 404 page that you want to test ...
Rails asset pipeline: Why relative paths can work in development, but break in production
The problem
When using the asset pipeline your assets (images, javascripts, stylesheets, fonts) live in folders inside app:
app/assets/fonts
app/assets/images
app/assets/javascripts
app/assets/stylesheets
With the asset pipeline, you can use the full power of Ruby to generate assets. E.g. you can have ERB tags in your Javascript. Or you can have an ERB template which generates Haml which generates HTML. You can chain as many preprocessors as you want.
When you deploy, Rails runs assets:precompile...
Upgrade guide for moving a Rails app from Webpack 3 to Webpack 4
Webpacker is Rails' way of integrating Webpack, and version 4 has been released just a few days ago, allowing us to use Webpack 4.
I successfully upgraded an existing real-world Webpack 3 application. Below are notes on everything that I encountered.
Note that we prefer not using the Rails asset pipeline at all and serving all assets through Webpack for the sake of consistency.
Preparations
- Remove version locks in
Gemfileforwebpacker - Remove version locks in
package.jsonforwebpackandwebpack-dev-server - Install by ca...