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
...
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...
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...
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'
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...
8 steps for fixing other people's code
Guide how to make fixes in other people's GitHub repositories. It's basically "Open Source Development 101".
Way back in mid-2007, when Rails 1.2 was the new hotness and GitHub was still a year away from crawling out of the primordial internet soup, prolific open source contributor Dr Nic wrote an article titled “8 steps for fixing other people’s code”. (...)
Here in the fantastical future world of 2012, while we still don’t have hoverboards or household nuclear fusion, we do have some great tools that make fixing other people’s code...
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
PSA: Chrome and Firefox do not always clear session cookies on exit
Cookies without an expiration timestamp are called "session cookies". [1] They should only be kept until the end of the browsing session.
However, when Chrome or Firefox are configured to reopen tabs from last time upon start, they will keep session cookies when closing the browser. This even applies to tabs that were closed before shutting down the browser.
This is by design in Chrome and [Firefox](https://bugzilla.mozilla.org/buglist.cgi?bug_id=337551,345830,358042,362212,36...
Minidusen: Low-tech record filtering with LIKE queries
We have a new gem Minidusen which extracts Dusen's query parsing and LIKE query functionality.
Minidusen can no longer index text in MySQL FULLTEXT columns, which was hardly used and didn't always help performance due to the cost of reindexing.
Minidusen is currently compatible with MySQL, PostgreSQL, Rails 3.2, Rails 4.2 and Rails 5.0.
Basic Usage
Our example will be a simple address book:
class Contact < ActiveRecord::Base
validates_presence_of :name, :street, :city, :e...
Retrieving the class an ActiveRecord scope is based on
Edge Rider gives your relations a method #origin_class that returns the class the relation is based on.
This is useful e.g. to perform unscoped record look-up.
Post.recent.origin_class
# => Post
Note that #origin_class it roughly equivalent to the blockless form of #unscoped from Rails 3.2+, but it works consistently across all Rails versions. #unscoped does not exist for Rails 2 and is broken in Rails 3.0.
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...
Re-enable submit buttons disabled by the :disable_with option
Submit buttons in Rails come with a useful option :disable_with which will disable the button when clicked and change its label to something like "Please wait...".
An annoying side effect of that feature is that when you use the back button to return to the form, the submit button will be greyed out and disabled.
A solution is to re-enable the submit button before leaving the page. This works in Rails 3:
$(window).unload(function() {
$.rails.enableFormElements($($.rails.formSubmitSelector));
});
Bulk-change multiple table rows in a migration
Using rename_column, remove_column, etc. more than once in a migration makes that migration run slower than it should. Use change_table instead.
Consider this migration:
add_column :users, :name, :string
remove_column :users, :first_name
remove_column :users, :last_name
rename_column :users, :cool, :awesome
Migrating in this case means that all those commands are processed step by step, causing 4 SQL statements to change the table. In turn, your database needs to modify the table structure 4 times. When working on hu...
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.
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...
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...
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...
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
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...
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...