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
spec
folder (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...
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.
Caution: `.includes` can make `.ids` non-unique.
This can happen with a very simple model:
class Note
has_many :attachments
end
Everything looks normal:
Note.all.to_a.size # => 8
Note.all.ids.size # => 8
Then .includes
leads to weird results:
Note.all.includes(:attachments).to_a.size # => 8
Note.all.includes(:attachments).ids.size # => 12
If a note has 5 attachments, its id will be included 5 times.
With .preload
it works as expected:
Note.all.preload(:attachments).to_a.size # => 8
Note.all.preload(:attachments).ids.size # => 8
Note
I crea...
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...
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...
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...
Linux Performance Analysis in 60,000 Milliseconds
You login to a Linux server with a performance issue: what do you check in the first minute?
uptime
dmesg | tail
vmstat 1
mpstat -P ALL 1
pidstat 1
iostat -xz 1
free -m
sar -n DEV 1
sar -n TCP,ETCP 1
top
Also see:
IRB's multi-line autocomplete and how to disable it
Recent IRB versions include a multi-line autocomplete which may be helpful to novice users but can be distracting.
Cycling through options works by pressing the Tab key (as usual), and for some methods you also get some kind of documentation, though the quality of results is usually not on par with your IDE of choice.
I have found that it also slows down my IRB in some cases, or that pressing the Backspace key does not always reliably remove characters, which I find more annoying than useful.
You may disable multi-line autocomplete by
- ...
Designing HTML emails
The 90s are calling: they want their tables back. Unfortunately, you need them all for laying out your HTML emails.
Email client HTML rendering is way more scattered than browser HTML. While you might have a pretty good understanding of what features and patterns you can use to support all major browsers, I doubt anyone masters this craft for HTML email clients.
The only way to ensure your email looks good (acceptable, at least) in all mail clients, is to check it. Litmus is your go-to solution for this (see below). W...
Ruby constant lookup: The good, the bad and the ugly
In Ruby, classes and modules are called constants. This card explains how Ruby resolves the meaning of a constant.
The good
E. g. in the following example, Array
could mean either Foo::Array
or simply Array
:
class Foo
def list
Array.new
end
end
What Ruby does here is to see if the name Array
makes sense inside of Foo::
, and if that fails, resolves it to ::Array
(without a namespace).
The bad
This is relevant for old Ruby versions. Ruby 2.5+ removes top-level constant lookup whi...
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)...
Spreewald 4.3.3 released
Field error steps
Spreewald's The ... field should have an error
and The ... field should have the error ...
steps now have built-in support for Rails and Bootstrap (v3-v5) error classes. When using Bootstrap, it is no longer necessary to overwrite the steps in your project.
At the same time, support for formtastic has been removed as there were no real use cases. Due to that, no breaking change was introduced, as the amount of users affected by this should be zero (it was neither in the documentation nor tested).
Users may now add...
Thread-safe collections in Ruby
When using threads, you must make your code thread-safe. This can be done by either locking (mutexes) all data shared between threads, or by only using immutable data structures. Ruby core classes like String
or Array
are not immutable.
There are several gems providing thread-safe collection classes in Ruby.
concurrent-ruby
The concurrent-ruby gem provides thread-safe versions of Array
and Hash
:
sa = Concurrent::Array.new # supports standard Array.new forms
sh = Co...
Geordi 1.3 released
Changes:
- Geordi is now (partially) tested with Cucumber. Yay!
- geordi cucumber supports a new @solo tag. Scenarios tagged with
@solo
will be excluded from parallel runs, and run sequentially in a second run - Support for Capistrano 2 AND 3 (will deploy without
:migrations
on Capistrano 3) - Now requires a
.firefox-version
file 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 ...
Email validation regex
There is a practical short list for valid/invalid example email addresses - Thanks to Florian L.! The definition for valid emails (RFC 5322) can be unhandy for some reasons, though.
Since Ruby 2.3, Ruby's URI lib provides a built-in email regex URI::MailTo::EMAIL_REGEXP
. That's the best solution to work with.
/\A[a-zA-Z0-9.!\#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[...
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...
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 @import
s 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 = ...