Upgrading from Capistrano 2 to 3
Capistrano 3 is a major rework of the framework and requires several adjustments to your deploy configuration files. The biggest change is that they moved away from their custom DSL and use Rake instead. For connecting with and operating on the servers, they bring a new gem SSHKit which does the heavy lifting. It's SSHKit's DSL that is used anywhere inside the Rake tasks. See #Resources at the bottom for examples.
Step 1: Upgrade guide
For migration from 2 to 3, follow this tutorial: [Capistrano 3 Upgrade Guide](https://semaphorec...
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'
Fix error: Missing the mysql2 gem
So you got this error, even though your Gemfile bundles mysql2:
!!! Missing the mysql2 gem. Add it to your Gemfile: gem 'mysql2'
or
Please install the mysql adapter: `gem install activerecord-mysql-adapter` (mysql is not part of the bundle. Add it to Gemfile.)
The reason for this confusing error message is probably that your Gemfile says mysql2, but your database.yml still uses the mysql adapter. Change it to use the mysql2 adapter:
development:
adapter: mysql2
database: myproject_developm...
RSpec: How to test the content of a flash message in a request spec
The ActionDispatch module of Rails gives you the helper method flash to access the flash messages in a response.
describe PostsController, type: :request do
describe 'update' do
it 'shows a success message on update' do
post_record = create(:post)
put "/posts/#{post_record.id}"
# Same as @request.flash[:alert]
expect(flash[:alert]).to eq('Post updated successfully.')
end
end
end
Run a script on the server
You have to specify the environment with -e env_name or RAILS_ENV=env_name if you want to run a script on the server.
at Rails 2 it's script/runner
bundle exec script/runner -e env_name path/to/script.rb argument1 argument2 ...
at Rails 3 it's rails runner
RAILS_ENV=env_name bundle exec rails runner path/to/script.rb argument1 argument2 ...
Retrieve the SQL query a scope would produce in ActiveRecord
Rails 3
User.active.to_sql
Rails 2
Use either the Edge Rider or fake_arel gem to get #to_sql backported to Rails 2.
If you don't want to use a gem for this, you can do this with vanilla Rails 2:
User.active.construct_finder_sql({})
How to fix gsub on SafeBuffer objects
If you have an html_safe string, you won't be able to call gsub with a block and match reference variables like $1. They will be nil inside the block where you define replacements (as you already know).
This issue applies to both Rails 2 (with rails_xss) as well as Rails 3 applications.
Here is a fix to SafeBuffer#gsub. Note that it will only fix the $1 behavior, not give you a safe string in the end (see below).
Example
def test(input)...
Headless Chrome: Changing the Accept-Language header is not possible
It seems like changing the HTTP_ACCEPT_LANGUAGE is not possible for a headless chrome.
- On Ubuntu the headless Chrome derives the Accept-Language from the operation system
- Adding the option
options.add_argument('--lang=de')to theCapybara::Selenium::Driverhas no effect - Adding the preference
options.add_preference('intl.accept_languages', 'de')to theCapybara::Selenium::Driverhas only effects if the--headlessoption is skipped (see bug ticket #775911) - Cha...
We have deprecated Rack::SteadyETag
Rack::SteadyETag was a Rack middleware that generates the same default ETag for responses that only differ in XOR-masked CSRF tokens or CSP nonces.
We have deprecated Rack::SteadyETag. We instead recommend reconfiguring your Rails app so two requests to the same resource produce the same HTML for a given user.
Geordi 1.3 released
Changes:
- Geordi is now (partially) tested with Cucumber. Yay!
- geordi cucumber supports a new @solo tag. Scenarios tagged with
@solowill be excluded from parallel runs, and run sequentially in a second run - Support for Capistrano 2 AND 3 (will deploy without
:migrationson Capistrano 3) - Now requires a
.firefox-versionfile to set up a test firefox. By default now uses the system Firefox/a test Chrome/whatever and doesn't print warnings any more. -
geordi deploy --no-migrations(aliased-M): Deploy with `cap ...
RSpec: How to compare ISO 8601 time strings with milliseconds
Rails includes milliseconds in Time / DateTime objects when rendering them as JSON:
JSON.parse(User.last.to_json)['created_at']
#=> "2001-01-01T00:00:00.000+00:00"
In RSpec you might want to use .to_json instead of .iso8601 to use the build-in eq matcher:
it 'returns the created at attribute of a user' do
get '/users/1'
expect(JSON.parse(response.body)['created_at']).to eq(Time.parse('2001-01-01').to_json)
end
Otherwise the strings do not match:
DateTime.parse('2001-01-01').to_s (will defa...
Perform Sidekiq jobs immediately in development
# config/initializers/sidekiq.rb
# Perform Sidekiq jobs immediately in development,
# so you don't have to run a separate process.
# You'll also benefit from code reloading.
if Rails.env.development?
require 'sidekiq/testing'
Sidekiq::Testing.inline!
end
Copy to clipboard without flash (clipboard.js)
We used zeroclipboard.js in some of our projects but now we switched to clipboard.js because it does not rely on flash. Flash support of the major browsers has ended.
Some more advantages of clipboard.js:
- it consists only of a single javascript file, so it does not trigger additional requests with rails
- it automagically provides user feedback by selecting the text it has copied
- it provides callbacks for success and error which make it easier to add custom behaviour after copying to the clipboar...
Heads up: Byebug has problems with zeitwerk
I encountered a unlucky behavior of byebug 11.1.3 (the most recent version at time of writing) when using it with Rails 6 and it's new autoloading component, zeitwerk. There already is a issue for that, so I hope it will be fixed with a future release.
The following test succeeds:
context 'factories' do
let(:test_case) { FactoryBot.create(:test_case) }
it 'are valid' do
expect(test_case).to be_valid
end
end
But when I did the same in byebug the foll...
Render Sass stylesheets dynamically
If - for whatever reason - you have to render stylesheets dynamically, the following snippet might be of help. It emulates what "sprockets" would to when precompiling your assets, and give your stylesheets access to all the regular bells and whistles (like asset_path, proper @imports etc):
class DynamicStylesheetsController < ApplicationController
def show
logical_path = RELATIVE_PATH_TO_YOUR_TEMPLATE
path = File.join(Rails.root, logical_path)
template = Sass::Rails::SassTemplate.new(path)
environment = ...
Postgresql: Paginate and count in one query using window functions
When paginating records, we usually need to know the number of total records in order to render pagination links. Popular pagination libraries like will_paginate or Kaminari do this for us by simply issuing an extra query, like this:
SELECT post.* FROM posts LIMIT 20 OFFSET 100;
SELECT COUNT(*) FROM posts;
This is fine most of the time. But rarely, you might have very complicated WHERE conditions or a subquery that takes time to run. In thes...
Test redirects to an external URL with Cucumber/Capybara
When a controller action redirects to an external URL (like http://somehost.com/some/path) you will find that this is hard to test with Cucumber and Capybara:
- A non-Javascript Rack::Test scenario will just ignore the host and try to open
/some/pathin your local application - A Selenium test will actually follow the redirect, which you probably don't want either
There are two workarounds for this. You can use either, or a combination of both.
- Write a controller spec
Controller specs can test if a resp...
Asset Pipeline Basics
The Rails asset pipeline improves delivery of application assets (javascripts, stylesheets, images, fonts). Here are some basic facts about its inner workings.
No magic
Manifests are the handle on your assets:
app/assets/stylesheets/application.css # use via: stylesheet_link_tag 'application'
The asset pipeline only considers files you explicitly require within your manifest files. The most common directives used in manifests are require some/file and require_tree some/directory. Paths may be **relative to the current director...
Careful when writing to has_many :through associations
tl;dr: Using has_many associations with a :through option can lead to lost or duplicate records. You should avoid them, or only use them to read records.
Consider this:
class User < ActiveRecord::Base
end
class Party < ActiveRecord::Base
has_many :invitations
has_many :users, through: :invitations, include: :user, order: 'users.name'
end
class Invitation < ActiveRecord::Base
belongs_to :party
belongs_to :user
after_create :send_invite
def send_invite
...
How to fix: Gems are unavailable although they are installed
- If Rails or Rake are complaining about a missing gem that is listed in your
Gemfile.lockand the listed version is properly installed, something is seriously wrong and needs to be fixed. - If you accidently executed
bundle install some_gemalthough you wantedbundle update some_gem
What is wrong
Let's say your Gemfile asks for some-gem which you can see when running gem list but bundle show some-gem just gives you an error:
Could not find gem 'some-gem', in any of the sources
Another indicator: Doing a `...
How to mount a legacy database to migrate data
There are many approaches out there how you can import data from a legacy application to a new application. Here is an approach which opens two database connections and uses active record for the legacy system, too:
1. Add you database information to you config/database.yml.
data_migration:
database: your_application_data_migration
2. Create a separate application record for the data migration, e.g. in app/data_migration/migration_record.rb. You will need to create an app/data_migration.rb class first.
class DataMig...
Nicer alternatives to def_delegator or def_delegators
Delegating methods to other objects is often helpful but the syntax of both def_delegators and def_delegator is a complete mess that makes your code hard to read.
Consider these classes:
class Topic < ActiveRecord::Base
def title
"A title"
end
def category
"Topic category"
end
end
class Post < ActiveRecord::Base
belongs_to :topic
def_delegato...
New Firefox and gem versions for our Selenium testing environment (Ubuntu 14.04+)
Firefox 5.0.1, which we were using for most Rails 2.3 projects, does not run on Ubuntu 14.04 any more. Here is how to update affected projects.
-
Update (or create)
.firefox-versionwith the content:24.0
If you haven't installed Firefox 24 yet, the next time you run tests with Geordi, it will tell you how to install it. -
On a Rails 2 project:
-
Update your Cucumber-related gems as described in Upgrading Cucumber and Capybara, including
cucumber_spinnerandlaunchy. -
If you...
-
Pimp my IRB
Put the attached files into your home directory and enjoy.
.irbrc
- defines
interesting_methods, which is essentially all methods without top-level methods inherited from Object/Module - requires
awesome_print, if present - requires
interactive_editor, if present (basically makes vim available) - loads .irbrc_rails if in Rails (e.g. for the Rails console)
.irbrc_rails
- defines
efind(email), which is a shortcut to find users by email
...