Ruby: Removing leading whitespace from HEREDOCs
If you're on Ruby 2.3+ there's a <<~ operator to automatically unindent HEREDOCs:
str = <<~MESSAGE
Hello Universe!
This is me.
Bye!
MESSAGE
If you have an older Ruby, you can use the String#strip_heredoc method from ActiveSupport. See Summarizing heredoc in ruby and rails for an example.
Technically...
A non-weird replacement for grouped_collection_select
Rails comes with grouped_collection_select that appears to be useful, but isn't.
As an alternative, consider the flat_grouped_collection_select found below. It takes a third argument that extracts the group from each element in the collection:
= form.flat_grouped_collection_select :user_id, users, :department, :id, :full_name
Here is the monkey-patch:
class ActionView::Helpers::FormBuilder
def flat_grouped_collection_selec...
Migrating to RSpec 2 from RSpec 1
You will need to upgrade to RSpec >= 2 and rspec-rails >= 2 for Rails 3. Here are some hints to get started:
- In RSpec 2 the executable is
rspec, notspec. - RSpec and rspec-rails have been completely refactored internally. All RSpec classes have been renamed from
Spec::SomethingtoRSpec::Something. This also means that everyrequire 'spec/something'must now berequire 'rspec/something'. - In
spec_helper.rb,Spec::Runner.configurebecomesRSpec.configure - It has become really hard to extend specific example groups ...
Disabling Spring when debugging
Spring is a Rails application preloader. When debugging e.g. the rails gem, you'll be wondering why your raise, puts or debugger debugging statements have no effect. That's because Spring preloads and caches your application once and all consecutive calls to it will not see any changes in your debugged gem.
Howto
Disable spring with export DISABLE_SPRING=1 in your terminal. That will keep Spring at bay in that terminal session.
In Ruby, [you can only write environment variables that subproc...
A saner alternative to SimpleForm's :grouped_select input type
SimpleForm is a great approach to simplifying your forms, and it comes with lots of well-defined input types. However, the :grouped_select type seems to be overly complicated for most use cases.
Example
Consider this example, from the documentation:
form.input :country_id, collection: @continents,
as: :grouped_select, group_method: :countries
While that looks easy enough at a first glance, look closer. The example passes @continents for a country_id.\
SimpleForm actua...
How to migrate CoffeeScript files from Sprockets to Webpack(er)
If you migrate a Rails application from Sprockets to Webpack(er), you can either transpile your CoffeeScript files to JavaScript or integrate a CoffeeScript compiler to your new process. This checklist can be used to achieve the latter.
- If you need to continue exposing your CoffeeScript classes to the global namespace, define them on
windowdirectly:
-class @User
+class window.User
- Replace Sprocket's
requirestatement with Webpacker's...
How to: Solve gem loaded specs mutex
Use bundler > 1.15 to fix Gem::LOADED_SPECS_MUTEX (NameError).
Given the following project:
ruby -v
ruby 1.8.7
bundler -v
Bundler version 1.13.7
gem -v
1.8.30
rails -v
Rails 3.2.22.1
Running specs or features resulted in:
uninitialized constant Gem::LOADED_SPECS_MUTEX (NameError)
The previous settings described in Maximum version of Rubygems and Bundler for Ruby 1.8.7 and Rails 2.3 (even the rails version was rails 3.2 and not 2.3) seems not to work here, so I used (also described in the ca...
When sessions, cookies and Clearance tokens expire and how to change it
Expiration of Rails sessions
By default Rails sessions expire when the user closes her browser window.
To change this edit your config/initializers/session_store.rb like this:
ActionController::Base.session = {
:key => '...',
:secret => '...'
:expire_after => 10.years
}
In older Railses the initializer is not available. Set the option in the environment.rb instead:
config.action_controller.session = {
:key => '...',
:secret => '...'
...
Threads and processes in a Capybara/Selenium session
TLDR: This card explains which threads and processes interact with each other when you run a Selenium test with Capybara. This will help you understand "impossible" behavior of your tests.
When you run a Rack::Test (non-Javascript) test with Capybara, there is a single process in play. It runs both your test script and the server responding to the user interactions scripted by your test.
A Selenium (Javascript) test has a lot more moving parts:
- One process runs your test script. This is the process you...
Always show all form errors during development
You've been there: A form cannot be submitted, but you don't see a validation error because the field at fault has no corresponding input field on the form. Because this is usually a bug, you insert debug information listing all errors into the form view. And once the bug is fixed, you forget to take out that debug information.
There is a better way. By copying one of the attached initializers into config/initializers, your forms will always render a small box listing all form errors in the bottom right corner of the screen. This box is n...
Spec "content_for" calls in helpers
This only applies to RSpec below version 1.3.2. The issue has been fixed in RSpec 1.3.2, and most likely RSpec 2 and later versions.
When you have a helper that calls content_for and want to check its behavior you should probably write a feature instead. If you still want to do it, mind the following.
Consider this helper:
module LayoutHelper
def title(string)
content_for :title, string
string
end
end
Somewhere in the layout we'd then say something like this: `<%= yield :title %...</p>
Carrierwave: Using a nested directory structure for file system performance
When storing files for lots of records in the server's file system, Carrierwave's default store_dir approach may cause issues, because some directories will hold too many entries.
The default storage directory from the Carrierwave templates looks like so:
class ExampleUploader < CarrierWave::Uploader::Base
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
end
If you store files for 500k records, that store_dir's parent directory will have 500k sub-directories which will cause some...
Force absolute URLs for parts of a view or controller
You know that you can force absolute URLs throughout a response. Now you want to modify URLs similarly, but only in parts of a view (or controller) logic. Here is how.
Note: this has only been tested on a Rails 2 application. It should work similarly for Rails 3.
Put this into your ApplicationController:
def rewrite_options(*args)
options = super
options.merge!(:only_path => false) if @with_full_urls
options
end...
How to set up SMTP email delivery with a Gmail account
If you want to make your Rails application be capable of sending SMTP emails, check out the action mailer configuration section in the Ruby on Rails guide.
TL;DR you will end up having an smtp_settings hash that looks something like this:
smtp_settings = {
address: ...,
domain: ...,
port: ...,
user_name: ...,
password: ...,
authentication: ...,
tls: ...,
enable_starttls_auto: ...,
}
This hash can be set as the `delivery_me...
How to disable cookies in cucumber tests
Unfortunately, Capybara does not offer a switch to disable cookies in your test browser. However, you can work around that by using a tiny Rack middleware -- it works for both Selenium and non-Selenium tests.
Wouldn't it be nice to say something like this?
Given cookies are disabled
When I try to sign in
Then I should see "Can't sign you in. Please enable cookies."
You can! Put the code below into some place like lib/rack/cookie_stripper.rb.
module Rack
class CookieStripper
ENABLED = false
...
Fix warning: No secret option provided to Rack::Session::Cookie
You will get this when you are using the latest version of Rails with a recent version of Rack:
SECURITY WARNING: No secret option provided to Rack::Session::Cookie.
This poses a security threat. It is strongly recommended that you
provide a secret to prevent exploits that may be possible from crafted
cookies. This will not be supported in future versions of Rack, and
future versions will even invalidate your existing user cookies.
The warning is caused by Rails calling Rack incorrectly. [It is unclear](https://github.c...
PostgreSQL: How to show table sizes
When you have a large PG database, you may want to find out which tables are consuming the most disk space.
You can easily check this using the following SQL statement from the PostgreSQL wiki.
SELECT nspname || '.' || relname AS "relation",
pg_size_pretty(pg_total_relation_size(C.oid)) AS "total_size"
FROM pg_class C
LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
WHERE nspname NOT IN ('pg_catalog', 'information_schema')
AND C.relkind <> 'i'
AND nspname !~ '^pg_toast'
ORDER BY pg_tot...
Using RSpec stubs and mocks in Cucumber
By default, Cucumber uses mocha. This note shows to use RSpec stubs and mocks instead.
Rspec 1 / Rails 2
Put the following into your env.rb:
require 'spec/stubs/cucumber'
Rspec 2 / Rails 3
Put the following into your env.rb:
require 'cucumber/rspec/doubles'
Note: Since Cucumber 4 it is important to require these lines in the env.rb and not any other file in support/* to register the hooks after any other After hook in support/*. Otherwise your doubles are removed, while other After steps requi...
Safely chain scopes with hash conditions
There is a nasty bug in all version of Rails 2 and some versions of Rails 3.x where two chained scopes with hash conditions on the same attribute would overwrite each other.
This is a horrible security issue if you are using scopes to limit what a user may see or change.
Workaround
If you are using an affected Rails version and cannot switch to a fixed version, you can use this manual workaround....
Gem development: When your specs don't see dependencies from your Gemfile
When you develop a gem and you have a Gemfile in your project directory, you might be surprised that your gem dependencies aren't already required in your specs. Here is some info that should help you out:
- Bundler actually doesn't automatically require anything. You need to call
Bundler.require(:default, :your_custom_group1, ...)for that. The reason why you never had to write this line is that Rails does this for you when it boots the environment. - That also means that if you have an embedded Rails app in your
specfolder (like [h...
How to remove properties of ActiveRecord scopes
When dealing with AR scopes, you can remove conditions, order, etc by using the unscope method.
It is available on Rails 4+.
Examples
Consider an exemplary User class as follows. For the examples below, we will use a scope that applies all its constraints.
class User < ActiveRecord::Base
scope :active, -> { where(locked: false) }
scope :admins, -> { where(role: 'admin') }
scope :ordered, -> { order(:name) }
end
users = User.active.admins.ordered
^
SELECT "users".* FROM "users" WHERE "use...
Fixing wall of net/protocol warnings
After upgrading to Rails 6.1.7.2 one of our apps printed a wall of warnings while booting:
/var/www/app/shared/bundle/ruby/2.6.0/gems/net-protocol-0.2.1/lib/net/protocol.rb:68: warning: already initialized constant Net::ProtocRetryError
/home/deploy-app/.rbenv/versions/2.6.10/lib/ruby/2.6.0/net/protocol.rb:66: warning: previous definition of ProtocRetryError was here
/var/www/app/shared/bundle/ruby/2.6.0/gems/net-protocol-0.2.1/lib/net/protocol.rb:214: warning: already initialized constant Net::BufferedIO::BUFSIZE
/home/deploy-app/.rben...
Upgrading Ruby from 1.8.7 to 2.3.5
Suggested Workflow
Set the ruby version in .ruby-version to 2.3.5, then perform these steps one by one, fixing errors as they occur:
- Update gems as listed below, and bundle
- Boot a Rails console - see below for a list of changes you will probably need
- Run Specs with
--backtraceoption - Run Cucumber features (with Geordi's
--debugoption) - When all tests are green, look through your Gemfile and remove as many version constraints as possible.
- Boot the application in different environements to spot further issues, e...
Make Less interpret the escape codes in a logfile
The unix command line tool less is a good choice for browsing logfiles. In the standard configuration, though, it does not interpret the escape sequences used in the rails logfiles. To enable this type:
less -R my_logfile.log
You can also have an alias to save yourself the typing
alias less='less -R'