Unfreeze a frozen ActiveRecord
You can freeze any Ruby object to prevent further modification.
If you freeze an ActiveRecord and try to set an attribute you will an error like this:
can't modify frozen hash
This is because ActiveRecord delegates #freeze
to its attributes hash.
You can unfreeze most Ruby objects by creating a shallow copy of the frozen object by calling #dup
on it:
user = User.find(3)
user.freeze
unfrozen_user = user.dup
Notes for Rails 2 users
-----------------...
RSpec: Tagging examples and example groups
In RSpec you can tag examples or example groups with any tags you like simply by saying
describe ReportCreator, slow: true do
# ..
end
describe ReportCreator do
it 'generates reports', slow: true do
# ...
end
end
You can then only run examples with these tags.
rspec --tag slow
rspec -t slow
# Using the parallel_tests gem
rake "parallel:spec[,,--tag slow]"
Or you can run all examples except the ones with a certain tag:
rspec --tag ~slow # note the ~
rspec -t ~slow
# Using the parallel_tests gem
r...
Ruby: How to grow or shrink an array to a given size
If you want to grow a Ruby Array, you might find out about #fill
but it is not really what you are looking for. [1]
For arrays of unknown size that you want to grow or shrink to a fixed size, you need to define something yourself. Like the following.
Array.class_eval do
def in_size(expected_size, fill_with = nil)
sized = self[0, expected_size]
sized << fill_with while sized.size < expected_size
sized
end
end
Use it like this:
>> [1, 2, 3].in_size(5)
=> [1, 2, 3, nil, nil]
...
Rubymine: Code folding
Code folding is a very useful feature to me. It gives me a quick overview over a file and keeps me from scolling like a hamster in its wheel.
Keyboard shortcuts:
Collapse/expand current code block
strg -/+
Collapse/expand the whole file
strg ctrl -/+
When diving into Cucumber features or huge Ruby classes, I usually collapse all and the gradually expand what I need.
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...
Rails has a built-in slug generator
Today I learned that Ruby on Rails has shipped with a built-in slug generator since Rails 2.2:
> "What Up Dog".parameterize
=> "what-up-dog"
> "foo/bar".parameterize
=> "foo-bar"
> "äöüß".parameterize
=> "aouss"
Also see: Normalize characters in Ruby.
skorks/nesty
Nested exceptions for Ruby:
When you rescue an error and then re-raise your own, you don't have to lose track of what actually occured, you can keep/nest the old error in your own and the stacktrace will reflect the cause of the original error.
This is awesome when you classes convert exception classes. I now always subclass Nesty::NestedStandardError
instead of StandardError
for my own error classes.
About Exception#cause
Ruby 2.1 has a built-in mechanism with Exception#cause
, which serves a similiar purpos...
Differences between transactions and locking
Web applications can be used by multiple users at the same time. A typical application server like Passenger has multiple worker processes for a single app. In a distributed deployment setup like we use at makandra you will even have multiple application servers, each with their own worker pool.
This means that your code needs to deal with concurrent data access. The two main tools we use to cope with concurrency are database transactions and distributed locks. These two are not interchangeable. You ca...
Custom loggers in Ruby and Rails
File logger
If you need to log to a file you can use Ruby's Logger
class:
require 'logger'
log = Logger.new('log/mylog.log')
log.info 'Some information'
log.debug 'Debugging hints'
log.error StandardError.new('Something went wrong')
Logger
does a number of things well:
- Message type (info / debug / error) is logged
- Log entries are timestamped
- Writing log output is synchronized between threads
- Logged errors are printed with full backtraces
If you don't like the output format, you can define a custom formatter.
I ha...
Dusen (>0.5) now with "exclude from search"
Dusen (our search gem) is now capable of excluding words, phrases and qualified fields from search.
E.g. search for
included -excluded
"search this" -"not that"
topic:"Yes" -topic:"No"
This will soon also work in makandra cards!
Linux: Kill a process matching a partial name
This is useful to kill processes like ruby my-script.rb
:
pkill -f my-script.rb
With great power comes great responsibility.
Slack integration for deployments via Capistrano
You can hook into Slack when using Capistrano for deployment. The slackistrano gem does most of the heavy lifting for you. Its default messages are unobtrusive and can be adjusted easily.
When deploying, it posts to a Slack channel like this:
How to integrate
Integrating Slackistrano with Capistrano 3 is fairly simple.
- In your Slack, open menu → A...
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...
Exporting to Excel from Rails without a gem
See this Railscast.
Basically you can simply write views like index.xlsx.erb
:
<?xml version="1.0"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">
<Worksheet ss:Name="Sheet1">
<Table>
<Row>
<Cell><Data ss:Type="String">ID</Data></Ce...
Ruby: Enumerable#partition
If you want to sort values from an enumerable into two arrays based on whether they match a certain criteria or not, Enumerable#partition
can come in handy.
# Enumerable#partition returns two arrays,
# the first containing the elements of enum
# for which the block evaluates to true,
# the second containing the rest.
(1..6).partition { |v| n.even? } #=> [[2, 4, 6], [1, 3, 5]]
Works well with destructuring assignment, too.
even, odd = (1..6).partition { |n| n.ev...
How to coordinate distributed work with MySQL's GET_LOCK
The linked article explains how to get a database-wide lock without creating table rows:
This article explains how I replaced file-based methods to ensure only one running instance of a program with MySQL’s GET_LOCK function. The result is mutual exclusivity that works in a distributed environment, and it’s dead simple to implement.
Ruby implementation
An implementation as a Rubygem seems to be [with_advisory_lock](https:...
Using PostgreSQL and jsonb with Ruby on Rails
Postgres 9.4 introduces a new column type: jsonb
. json
and jsonb
columns store data differently, so just compare the two when you want to store JSON data and choose the one that matches your use case best.
Rails 4.2 includes support for jsonb
columns, too. The article outlines different ways on how to interact with the serialized object.
Ruby: Counting occurrences of an item in an array / enumerable
Enumerable#count
can do three things.
- With no argument provided, it returns the number of items.
- With an argument, it returns the number of items matching the given value.
- With a block, it counts the number of elements yielding a truthy value.
ary = [1, 2, 4, 2]
ary.count #=> 4
ary.count(2) #=> 2
ary.count { |x| x % 2 == 0 } #=> 3
Ruby: Flatten arrays by only one level
Array#flatten
by default flattens an array recursively. To only flatten the array for e.g. one level, it takes an optional argument.
# Flattens the array recursively
>> [1, [2, [3]]].flatten
=> [1, 2, 3]
# Flattens the array the given number of times
>> [1, [2, [3]]].flatten(1)
=> [1, 2, [3]]
Fix error UDPSocket.open: wrong number of arguments (0 for 1)
I got the following error after updating the selenium-webdriver
gem:
wrong number of arguments (0 for 1) (ArgumentError)
/home/pointoo-dev/.rvm/gems/ruby-1.8.7-p374/gems/selenium-webdriver-2.35.1/lib/selenium/webdriver/common/platform.rb:183:in `open'
/home/pointoo-dev/.rvm/gems/ruby-1.8.7-p374/gems/selenium-webdriver-2.35.1/lib/selenium/webdriver/common/platform.rb:183:in `ip'
/home/pointoo-dev/.rvm/gems/ruby-1.8.7-p374/gems/selenium-webdriver-2.35.1/lib/selenium/webdriver/common/platform.rb:196:in `interfaces'
It was caused...
grosser/rspec-instafail
Gem to show failing specs instantly.
Unlike the --fail-fast
option it doesn't abort abort on the first failure, but keeps running other examples after print out the failure.
I haven't tried it with parallel_tests
.
Beware: Coffeescript "in" is not the Javascript "in"
The Javascript in
operator does what Hash#has_key?
does in Ruby: Return whether an object has a property.
However, Coffeescript has its own in
operator that checks for array inclusion. To check whether an object has a property, use of
:
Javascript
'name' in {name: 'Horst'} # => true
Coffeescript
# wrong
'name' in {name: 'Horst'} # => false
# correct
'name' of {name: 'Horst'} # => true
1 in [1,2,3] # => true
True story.
Ruby: Find a hash key given it's value
To find a hash key by it's value, i.e. reverse lookup, one can use Hash#key
. It's available in Ruby 1.9+.
Hash#key(value) → key
# => Returns the key of the first occurrence of a given value.
If the value is not found, returns nil.
hash = { "a" => 100, "b" => 200, "c" => 300, "d" => 300 }
hash.key(200) #=> "b"
hash.key(300) #=> "c"
hash.key(999) #=> nil
Delegating an instance method to a class method in Ruby
With ActiveSupport
you can say:
class Robot
def self.likes_humans?
'Nope.'
end
delegate :likes_humans?, to: :class
end
Robot.likes_humans?
# => 'Nope.'
Robot.new.likes_humans?
# => 'Nope.'