Silencing Deprecation Warnings in Rspec
If you’re testing the behavior of deprecated code in your Ruby project, the warning messages littered throughout your spec output is incredibly noisy.
You could silence all warnings with ::ActiveSupport::Deprecation.silenced = true, but you might miss out on an important warning in one of your dependencies. It’s tempting to remove the tests altogether (the code will be burned soon too, right?), but I figured out something a little nicer a little while back in Formtastic’s test suite.
Iterate over every n-th element of a Range in Ruby
If you want to iterate over a Range, but only look at every n-th element, use the step
method:
(0..10).step(5).each do |i|
puts i
end
# Prints three lines:
# 0
# 5
# 10
This is useful e.g. to iterate over every Monday in a range of Dates
.
If you are using Rails or ActiveSupport, calling step
without a block will return an array of matching elements:
(0..10).step(5)
# => [0, 5, 10]
Default block arguments for Ruby 1.8.7
When your block takes an argument that should have an default, only in Ruby 1.9 you can say:
block = lambda do |message, options = {}|
# ...
end
If you are on Ruby 1.8.6 or 1.8.7 you must resort to the following workaround:
block = lambda do |*args|
message = args[0]
options = args[1] || {}
end
Overriding unary operators in Ruby
This must be one of the coolest, yet quite unknown, technique in Ruby. For certain types of problems (e.g. when you have a set of rules) this gives you such an elegant way of describing the solution. There’s no meta programming or monkey patching involved, it’s short and sweet and best of all: it’s very intuitive.
Word boundaries in MySQL regular expressions
In regular expressions you can use the zero-width pattern \b
to match the beginning or end of a word:
note.title =~ /\bfoo\b/
Unfortunately \b
is not available in MySQL. You can use [[:<:]]
and [[:>:]]
to match the beginning and end of a word instead:
SELECT * FROM notes WHERE title REGEXP "[[:<:]]foo[[:>:]]"
These markers are unique to MySQL and not available in Ruby regular expressions.
RSpec matcher to check if two numbers are the same
You can usually just use the eq
matched to compare two numbers:
expect(deal.total).to eq(120)
If the actual value is a BigDecimal
, you might have issues when you match it against a Float
:
expect(deal.total_price).to eq(1200.99)
In these cases, try matching it against another BigDecimal
:
expect(deal.total_price).to eq BigDecimal(1200.99)
If you don't like the syntax, our rspec_candy gem has a matcher that will compare Fixnums
(integers), Floats
and `BigDecima...
The Ruby Infinite Hash
How to create an infinitely nestable hash that always defaults to a new hash if a key does not map to a value.
Force net/http to verify SSL certificates
Ruby's net/http is setup to never verify SSL certificates by default. Most ruby libraries do the same. That means that you're not verifying the identity of the server you're communicating with and are therefore exposed to man in the middle attacks. This gem monkey-patches net/http to force certificate verification and make turning it off impossible.
Capistrano cowboy deploys
Sometimes, you just need to shoot from the hip…or deploy your local changes without committing them. Put this snippet from Jesse Newland in ~/.caprc and now you can cap cowboy deploy.
Ruby: Checking if a class is a descendant of another class
If you want to find out whether a Class object is directly inheriting from another class, use superclass
:
ActiveRecord::RecordNotFound.super_class == ActiveRecord::ActiveRecordError # => true
To check if another class is an ancestor (not necessarily the direct superclass, but e.g. the superclass of the superclass):
ActiveRecord::RecordNotFound.ancestors.include?(StandardError) # => true
Note that ancestors
also includes the receiving class itself as well as any included modules (which is quite...
Check if two arrays contain the same elements in Ruby, RSpec or Test::Unit
RSpec 1, RSpec 2
To test whether two arrays have the same elements regardless of order, RSpec 1 and 2 give you the =~
matcher:
actual_array.should =~ expected_array
Rspec 3
With RSpec 3's expect
syntax you can choose one of these two matchers:
expect(actual_array).to match_array(['1', '2', '3'])
expect(actual_array).to contain_exactly('1', '2', '3')
Note how match_array
takes an argument, but contain_exactly
takes a list of elements as varargs.
Test::Unit
If y...
Encode or decode HTML entities
Use the htmlentities gem.
Encoding works like this:
require 'htmlentities'
coder = HTMLEntities.new
string = "<élan>"
coder.encode(string) # => "<élan>"
coder.encode(string, :named) # => "<élan>"
coder.encode(string, :decimal) # => "<élan>"
coder.encode(string, :hexadecimal) # => "<élan>"
Decoding works like this:
require 'htmlentities'
coder = HTMLEntities.new
string = "élan"
cod...
Never use YAML.load with user input
You can get YAML.load
to instantiate any Ruby object by embedding the desired class name into the YAML code. E.g. the following will create a new User
object and set @email
and @password
to the given values:
--- !ruby/object:User
email: me@somewhere.com
password: secret
Considering the security implications, you should never trust YAML from untrusted sources. If you are looking for a simple, secure and readable data transfer format, use Object#to_json
and JSON.parse
.
Another way around YAML.load
is [`YAML.safe_...
Open a page in the default browser
Use the Launchy gem:
Launchy.open('http://www.ruby-lang.org/')
Change the current directory without side effects in Ruby
To temporarily change the current working directory in Ruby, call Dir.chdir
with a block. The previous working directory will be restored when the block ends:
Dir.chdir('/usr/local') do
# do stuff in /usr/local
end
Ruby 2.0 Refinements in Practice
The first thing you need to understand is that the purpose of refinements in Ruby 2.0 is to make monkey-patching safer. Specifically, the goal is to make it possible to extend core classes, but to limit the effect of those extensions to a particular area of code. Since the purpose of this feature is make monkey-patching safer, let’s take a look at a dangerous case of monkey-patching and see how this new feature would improve the situation.
MySQL: Select a default value for NULL fields
If you need to do calculations inside the database and can not use Ruby objects you may run into problems when encountering fields with NULL values:
SELECT foo, bar, foo - bar AS baz FROM plop;
+-----+------+------+
| foo | bar | baz |
+-----+------+------+
| 30 | 20 | 10 |
| 30 | NULL | NULL |
+-----+------+------+
Solve this by using IFNULL
: it returns the selected value if present and a given alternative if it would select NULL:
SELECT foo, bar, foo - IFNULL(bar, 0) AS baz FROM plop;
+-...
Virtual attributes for array fields
When a has_many
association basically serves to store a list of associated strings (tags, categories, ...), it can be convenient to represent this association as a string array in the containing model. Here is an example for this pattern from the acts-as-taggable-on gem:
post = Post.last
p post.tag_list # ['foo', 'bar', 'baz']
post.tag_list = ['bam']
p post.tag_list # ['bam']
This string array tag_list
is magical in several ways:
- It is read from and written to a `has...
Install RubyMine under Ubuntu
This card explains how to install RubyMine for the first time. If you want to upgrade an existing RubyMine installation (after legacy install) to a newer version, see How to upgrade RubyMine.
Option A (new way)
Ubuntu 16.04 comes with snap, a way to package software with all its dependencies. RubyMine is also packaged as a snap.
A snap will always track a channel
(like stable
, beta
) and automatically update to the newest version available in this channel. By default the snap daemon will check for ...
Installing Nokogiri
Because Nokogiri needs to be compiled and dynamically linked against both libxml2 and libxslt, it has gained a reputation for being complicated to install. Let’s wrassle this little myth to the ground, shall we?
Hunt down that elusive debug message in Ruby
When you just went through a long debug-fest and infested your code with dozens of debug messages, it can be hard to find all those calls to puts
and p
. This note describes a hack that lets you trace those messages in your code.
Let's say you want to get rid of a console message "foobar". Copy the Undebug
class below to config/initializers.rb
. In the same initializer, type a line:
Undebug.trace_message('foobar')
Now run tests or whatever you need to do to to trigger that message. The console output should look like this:
...
Take care when joining and selecting on scopes
Occasionally some complex query must be processed on the database because building thousands of Ruby objects is impracticable.
Many times you would use scope options, like this:
users = User.scoped(
:joins => 'INNER JOIN orders joined_orders ON users.id = joined_orders.user_id',
:conditions => [ 'joined_orders.date BETWEEN ? AND ?', start_date, end_date ],
:select => '*, SUM(joined_orders.amount) AS amount_sum',
:group => 'users.id'
)
You get ActiveRecord objects and you can ask each of them about its `amou...
Manipulate an array attribute using multiple check boxes
E.g. when you're using a tagging gem, you have seen virtual attributes that get and set a string array:
post = Post.last
puts post.tag_list # ['foo', 'bar', 'baz']
post.tag_list = ['bam']
puts post.tag_list # ['bam']
If you would like to create a form displaying one check box per tag, you can do this:
- form_for @post do |form|
= form.check_box :tag_list, { :multiple => true }, 'foo', nil
= form.check_box :tag_list, { :multiple => true }, 'bar', nil
=...
Use the back button in Cucumber
In order to go back one page in your Cucumber tests, you can use the following step definition for Capybara:
When(/^I go back$/) do
visit page.driver.request.env['HTTP_REFERER']
end
If you're on Webrat, this should work:
When(/^I go back$/) do
visit request.env["HTTP_REFERER"])
end
An improved version of this step is now part of our gem spreewald on Github.