Ruby 2.3 new features
Ruby 2.3.0 has been around since end of 2015. It brings some pretty nice new features! Make sure to read the linked post with its many examples!
Hash#fetch_values
Similar to Hash#fetch, but for multiple values. Raises KeyError
when a key is missing.
attrs = User.last.attributes
attrs.fetch_values :name, :email
Hash#to_proc
Turns a Hash into a Proc that returns the corresponding value when called with a key. May be useful with enumerators like #map
:
attrs.to_proc.call(:name)
attrs.keys.grep(/name/).map &attrs...
Take care when merging with params
Be careful when using params.merge
as params
is a HashWithIndifferentAccess.
Why?
Usually this should not be an issue but it turns crazy if you try to include associated models deeper than 1 level:
options = params.merge(:include => { :user => :avatar })
Post.paginate options
When inspecting the merged params you will get something like this:
{ :include=> { "user" => :avatar }, :page => 23 }
Here the :user
symbol in the hash of inclusions turned into a "user"
...
Delete all MySQL records while keeping the database schema
You will occasionally need to clean out your database while keeping the schema intact, e.g. when someone inserted data in a migration or when you had to kill -9
a frozen test process.
Old Capybara versions already have the Database Cleaner gem as dependency. Otherwise add database_cleaner
to your *Gemfile`. This lets you say this from the Rails console:
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.cl...
Use Memoizer instead of ActiveSupport::Memoizable
ActiveSupport::Memoizable
will be removed from Rails and has a lot of strange caveats that will ruin your day.
Use the Memoizer gem instead. It works in all past and future Railses and has none of the annoying "features" of ActiveSupport::Memoizable
. It just does memoization and does it well.
The syntax is similiar also:
class Foo
include M...
Unexpected behavior when changing both an association and its foreign key attribute in ActiveRecord
When you set both a record's association and that association's foreign key attribute, Rails does not realize you are talking about the same thing. The association change will win in the next save
, even if the foreign key attribute was changed after the association.
As an example, assume you have these two models:
class Group < ActiveRecord::Base
has_many :users
end
class User < ActiveRecord::Base
validates_presence_of :group_id
belongs_to :group
end
We will now load a User
and change both its `g...
Split an array into columns
You know that you can collect an array as groups using in_groups
or in_groups_of
.
Maybe you want to fetch those values in "columns" where the first value lives in the first column, the second one in the second, etc. until it wraps, so that for example the fourth value is in the first of three columns.
Put the attached file into config/initializers/
to be able to say in_columns
on any Array
:
>> [1, 2, 3, 4, 5, 6, 7].in_columns(3)
=> [[1, 4, 7], [2, 5], [...
Capybara 2.0 has been released
The gem author Jonas Nicklas highlights in a Google Groups post that the release
- is not backwards compatible to 1.x versions of Capybara
- does not support Ruby 1.8.x anymore
- removes confusion with Rails' built in integration tests (you put capybara rspec integration tests into the
spec/feature/...
folder) and the:type
metadata has been changed from:request
to:feature
- throws exceptions when trying to interact with an element whose identifier is...
Marry Capybara with SSL-enabled applications
Capybara does not play nice with sites that have some actions protected by SSL, some not. A popular way to implement this in Rails is using the ssl_requirement plugin by DHH, which redirects a requests from HTTP to HTTPS if the requested action requires SSL and vice versa.
Capybara follows the redirect, but seems to forget the changed protocol for the next request. The only hack-free workaround right now is to use URLs in lieu of paths everywhere (links, form actions).
For a hackful fi...
Measuring sql query time of a piece of code using ActiveSupport::Notifications
ActiveSupport::Notifications provides an instrumentation API for Ruby. It is used throughout rails to publish instrumentation events that include information about each part of a request/response cycle.
Have a look at your application log file - yes, those are those events. The cool thing is that you can subscribe to those events.
There is also a convenience method that allows you to subscribe to those events only for the time of executing a block of code. Thus you can capture all sql queries that are triggered when executing your block....
Install a local Gemfile on a remote server
Call with the server's hostname (and user if you have no SSH agent), e.g.
install-gems-remotely my.server.com
# or without agent:
install-gems-remotely me@my.server.com
When you call it from a rails directory, it uploads your Gemfile
, Gemfile.lock
as well as the gemspecs of all vendored gems in to a temporary folder on the server and does a bundle install
there.
If you need to install gems from anothere Gemfile, just do it like this:
BUNDLE_GEMFILE=Gemfile.something; install-gems-remotely my.server.com
This scri...
How to encode or decode quoted-printable strings
E-mails are usually encoded using Quoted Printable. Here is how to decode or encode such strings.
You probably know Quoted Printable from e-mail bodies appearing in Rails logs, where =
s become =3D
s in URLs, or where long lines are split up and trailed by =
after each split.
Decode Quoted Printable
Decoding such strings is actually quite simple using plain Ruby:
"foo=3Dbar".unpack('M')[0]
# => "foo=bar"
Note that unpack
will return an array. Our result is the 1st item.
...
Multi-line Ruby block in Haml
There are several options, but most of them are impractical. The best way is to use the :ruby
filter:
:ruby
puts javascript_include_tag(
'lib/jquery-1.6.1.min.js',
'lib/jquery-rails-ujs.js',
'lib/jquery-ui-1.8.13.custom.min.js',
'lib/jquery.ui.datepicker-de.js',
'lib/jquery-ui-timepicker-addon.min.js',
'lib/jquery.tools.min.js',
'application.js',
'google-maps.js',
:cache => true
)
...
randym/axlsx · GitHub
Axlsx is an incredible gem to generate "Office Open XML" spreadsheet files (XLSX). Does not break on large spreadsheets and supports a ton of features like graphs.
API looks mature and existing code is easy to migrate when coming from the spreadsheet
gem.
The documentation of some methods is a bit out of date, but you'll find your way around the gem's code.
No support for reading files, however. :( If you want to open XLSX spreadsheets (for example to confirm your output in tests), you can use [roo
](h...
How to remove RSpec "old syntax" deprecation warnings
RSpec 3.0 deprecates the :should
way of writing specs for expecting things to happen.
However, if you have tests you cannot change (e.g. because they are inside a gem, spanning multiple versions of Rails and RSpec), you can explicitly allow the deprecated syntax.
Fix
Inside spec/spec_helpber.rb
, set rspec-expectations
’ and/or rspec-mocks
’ syntax as following:
RSpec.configure do |config|
# ...
config.mock_with :rspec do |c|
c.syntax = [:should, :expect]
...
Fixing "A copy of Klass has been removed from the module tree but is still active"
This can happen during development when classes without automatic reloading are pointing to classes with automatic reloading. E.g. some class in lib
is calling Model.static_method
.
Workaround A
Stop referencing autoloaded classes from static files. If you can't, see workaround B and C.
Workaround B
Make sure the offending file (the one referencing the autoloaded class) is autoloaded, too. You may do this:
# config/application.rb
config.paths.add 'offending/file/parent/directory', eager_load: true
Workaroun...
String#indent: Know your definitions!
String#indent
is not a standard Ruby method. When you use it, be sure to know where this method comes from. Many Gems shamelessly define this method for internal usage, and you'll never know when it may be removed (since it's usually not part of the Gem's API).
Unless you're using Rails 4 (which brings String#indent
in ActiveSupport), you'll be best of defining it yourself. This card has it for you.
Gems that define String#indent
(incomplete)
----------------------------...
Fix Capistrano warnings: Missing public directories
I got these warnings while deploying a Rails 3.2 app with asset pipeline enabled:
*** [err :: host.tld] find: `/opt/www/hollyapp.com/releases/20120503115342/public/images': No such file or directory
*** [err :: host.tld] find: `/opt/www/hollyapp.com/releases/20120503115342/public/stylesheets': No such file or directory
*** [err :: host.tld] find: `/opt/www/hollyapp.com/releases/20120503115342/public/javascripts': No such file or directory
Folders like public/javascripts
might not exist if you're using the asset pipeline (...
Machinist's #make breaks on has_many associations when defining method `empty?`
Observed on Rails 2.3 and machinist 1.0.6
Like the title says, when you define the method empty?
like in the following example, you may not longer use collection.make
.
class Book
has_many :pages
def empty?
pages.empty?
end
end
Assuming
b1 = Book.find(1)
b2 = Book.find(2)
instead of expected
b1.pages.make #=> #<Page id: 1, book_id: 1>
b2.pages.make #=> #<Page id: 2, book_id: 2>
you'll get
b1.pages.make #=> #<Page id: 1, book_id: 3>
b2.pages.make #=> #<Page id: 2,...
MySQL 5.6 slightly changes DECIMAL data type
About
A MySQL DECIMAL
column is used when it is important to preserve exact precision. It takes two parameters, where precision is the total number of digits and scale the number of digits to the right of the decimal point. A DECIMAL(6,2)
column may store numbers up to 9,999.99.
In Rails, a decimal column definition looks like this: t.decimal :amount, :precision => 6, :scale => 2
.
Issue
MySQL prior to 5.6 stored leading zeros (0003.1) and +/- characters (+2.1) within the column. However, **it would permit storing ...
Alternative to url_for's deprecated :overwrite_params option
If you have the following deprecation warning after upgrading to rails >= 2.3.10
DEPRECATION WARNING: The :overwrite_params option is deprecated. Specify all the necessary parameters instead.
that is for example caused by
url_for( :overwrite_params => { :order => 'name', :dir => 'asc' } )
you can fix this by using params.merge {:my_param_to_overwrite => 'foo' }
.
To fix the example above the code could look like:
url_for( params.merge { :order => 'name...
Mysterious "margin" below an image
Consider the following HTML & CSS:
<div><img src='http://makandra.com/images/makandra-ruby-on-rails.png' /></div>
^
img {
background-color: red;
}
div {
border: 1px solid black;
}
This will leave a margin of about 5px between the lower edge of the image and the containing div, although there are no paddings or margins set, and there's no whitespace. The reason is, the image will vertically align baseline
, and the space below the image is just kept for descenders (the part of letters below the basel...
Quickly printing data in columns on your Ruby console
Dump this method into your Ruby console to quickly print data in columns. This is helpful for e.g. comparing attributes of a set of Rails records.
def tp(objects, *method_names)
terminal_width = `tput cols`.to_i
cols = objects.count + 1 # Label column
col_width = (terminal_width / cols) - 1 # Column spacing
Array(method_names).map do |method_name|
cells = objects.map{ |o| o.send(method_name).inspect }
cells.unshift(method_name)
puts cells.map{ |cell| cell.to_s.ljust(col_width) }.join ' '
end
nil
end
Usag...
How to human-join an array in JavaScript
To simulate Rails' to_sentence
in your JavaScript application, you can use these few lines of CoffeeScript code:
joinSentence = (array) ->
if array.length > 1
array[0..-2].join(', ') + ', and ' + array[-1..]
else
array.join ', '
Examples:
> joinSentence(['cats', 'dogs', 'pandas'])
# => 'cats, dogs, and pandas'
^
> joinSentence(['llamas'])
# => 'llamas'
Here is some plain JavaScript, should you prefer that:
function joinSentence(array) {
if (array.length > 1) {
return ar...
Why you see a GET "/__identify__" request in Capybara tests
You might wonder about this request in your test.log
:
Started GET "/__identify__" for 127.0.0.1 at 2015-04-29 18:00:02 +0100
This is what happens: For drivers like Selenium, Capybara will boot up a Thin or Webrick server in a separate thread. It then makes a GET request to /__identify__
to see if the server is ready to accept requests.
Since you don't have a route that responds to /__identify
, Capybara will wrap your Rails app in...