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]
 ...

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 (...

Unicorn: How to force a single threaded boot in development

Unicorn allows you to specify the maximum number of workers. In development this could be useful if you use a debugger, but do not want to overflow the console with other request like from ActionCable. Then just set the maximum number of workers to 1 and the other requests have to wait.

UNICORN_WORKERS=1 rails server

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...

Asset pipeline may break Javascript for IE (but only on production)

If some of your JavaScripts fail on Internet Explorer, but only in staging or production environments, chances are that JavaScript compression is the culprit.

By default, Rails 3.2 compresses JavaScript with UglifyJS. I have seen a few cases where this actually breaks functioning JavaScript on IE (one example is the CKEditor).

I fixed this by switching to Yahoo's YUI Compressor.

To do this, do the following:

  • replace the uglifier gem with the yui-compressor gem...

Deal with error: Expected foo_trait.rb to define FooTrait

Lately, I came across a nasty error. I had a class Article that included FooTrait and BarTrait. In BarTrait, I then accidentally called a non-existent method:

has_defaults :dummy => Dummy.non_existent_method

From that moment, no page would load anymore but always display an exception: Expected foo_trait.rb to define FooTrait. That trait had nothing to do with BarTrait.

Since it doesn't tell you what's wrong, you either remember where you were working last or you need to check all [traits](https://github.com/makandra/modul...

PostgreSQL's OVERLAPS operator is not fully inclusive

PostgreSQL supports the SQL OVERLAPS operator. You can use it to test if two date ranges overlap:

=> SELECT ('2001-02-16'::date, '2001-12-21'::date) OVERLAPS
          ('2001-12-20'::date, '2002-10-30'::date);

overlaps
--------
true

An important caveat is that the date ranges are defined as start <= time < end. As such the later date is not included in the range:

=> SELECT ('2001-02-16'::date, '2001-12-21'::date) OVERLAPS
          ('2001-12-21'::date, '2002-10-30'::date);

overlaps
--------
false

Also compar...

has_defaults is now a gem

  • has_defaults is now a gem, no longer a plugin.
  • The plugin version no longer exists. Note that plugins are no longer supported in 3.2.
  • If you are working on an application that has the plugin version of has_defaults there is no advantage to be gained from upgrading the gem. The gem is there for you should you one day upgrade to Rails 3.2+.
  • Please don't use the defaults gem which we original forked away from in 2009. It sets defaults when a field is `bl...

How to fix strangely disappearing or misbehaving forms

You most likely have a form element inside another form element. Don't do that. Ever.

Firefox and Chrome will discard the first form nested inside another form (but for some reason keep others). Internet Explorer will possibly act like nothing is wrong -- but break (send the outer form) when you submit.

If your application behaves normal at first but removes forms from the DOM when you Ajax around, this could be the cause. Remember this note when you think your browsers are broken once again and check for such things thoroughly bef...

Namespacing: why `uninitialized constant` error may occour in `development` but not in `test` environment

Example:

  class Book::Page
  end
  
  class MyBook < Book
    def new_page
      Page.new # has to be `Book::Page` in development to make it work 
    end
  end

Method new_page may throw an error when it was called during browser interaction in development but doesn't make the test fail.

The reason

Development autoloading isn't smart enough to find the referenced class
At other environments (test, staging, production) autoloading is disabled, that all classes are already loaded when browser interaction takes place what makes...

How to find out if you are in Cucumber or in RSpec

Sometimes you need a piece of code to do something different for specs than for features. If you don't have separate environments, you can't check your Rails.env.

I managed to distinguish between specs and features by asking Capybara.

Note that this only works when you do not use Capybara in specs.

if defined?(Capybara) and Capybara.respond_to?(:current_driver)
  # you're in a Cucumber scenario
else
  # you're probably in a spec
end

You could omit the defined?(Capybara) condition, if you are sure that Capybara...

Distance of time in what you like: days, months, years

Sometimes the Rails helper #distance_of_time_in_words is using too much magic.
When you need a time difference in a specific unit, use this method:
^
def distance_of_time_in(unit, from, to)
diff = to - from

  if 1.respond_to? unit
    distance = diff / 1.send(unit)
    distance.abs.round
  else
    raise ArgumentError, "#{unit.inspect} is not supported as unit"
  end
end

distance_of_time_in(:days, Time.now, 1.year.ago)
=> 365

Remove the .abs if you want the mathematical *differ...

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]

Cucumber: Detect if the current Capybara driver supports Javascript

Copy the attached file to features/support. This gets you a convenience method:

Capybara.javascript_test?

Is true for Selenium, capybara-webkit, Poltergeist and a custom driver called :chrome (which we sometimes like to use for Selenium+Chrome).

Similar sounding but completely different card: Detect if a Javascript is running under Selenium WebDriver (with Rails)

Webrat doesn't follow redirect because it considers the url external

Rails doesn't know which host it is running on. For generating links, it strips the hostname off the request URL, which can lead to errors when you have absolute URLs in your Cucumber tests.

If you really need to use absolute URLs somewhere, say in an email you send, either throw away the host when parsing it (e.g. body.scan(/http:\/\/[^\/]+\/([^\s"<]+)/)) or tell Webrat you're back on your site.