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.

Different behavior for BigDecimal#floor in Ruby 1.8 and Ruby 1.9

Ruby 1.8 (supplied by Rails' ActiveSupport)

>> BigDecimal.new("0.1").floor.class
=> BigDecimal

Ruby 1.9 (supplied by Ruby 1.9 itself)

>> BigDecimal.new("0.1").floor.class
=> Fixnum

In fact, Float#floor has changed from Ruby1.8 to Ruby 1.9 which is used by BigDecimal#floor internally.

Attached initializer backports Ruby 1.9 behavior to Ruby 1.8.

How to fix webpack-dev-server not found

The bin/webpack-dev-server command is not as smart as e.g. rails server, where it shows the proper fix within the error message.

$ bin/webpack-dev-server                                                                  
yarn run v1.19.1
error Command "webpack-dev-server" not found.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Run yarn install --check-files to fix this error.

Fix when assigning nested attributes raises "undefined method `to_sym' for nil:NilClass"

You might have a table without a primary key set in MySQL.

You can fix this by adding a primary key index to the guilty MySQL table, or by setting self.primary_key = "id" in your class definition.

Related, but different issue: Rails 2 does not find an association when it is named with a string instead of a symbol

Customize path for Capybara "show me the page" files

When you regularly make use of Cucumber's "show me the page" step (or let pages pop up as errors occur), the capybara-20120326132013.html files will clutter up your Rails root directory.

To tell Capybara where it should save those files instead, put this into features/support/env.rb:

Capybara.save_and_open_page_path = 'tmp/capybara'

Why your Cucumber feature loses cookies when run under Selenium

When your Cucumber feature seems to forget cookies / sessions when you run it with Selenium check if the test travels in time like here:

Given the date is 2017-10-20
When I sign in
Then I should see "Welcome!"

What happens here is that the Rails application serving pages runs in 2017, but the process running your browser still lives today. This huge gap in time will expire most cookies immediately.

If all you need is to freeze the time to a date, a workaround is to travel to the future instead.

Refile: Ruby file uploads, take 3

Jonas Nicklas, the author of Carrierwave and Capybara, has released Refile, a gem for handling file uploads in Rails. It handles direct uploads (also direct uploads to Amazon S3) better than Carrierwave.

The story and reasoning behind some of the decisions in Refile, and how it's different from Carrierwave, by the author himself, is a good read before deciding which way you'll go.

Big Caveat: Refile only stores the original image and r...

Look up a gem's version history

Sometimes it might be helpful to have a version history for a gem, e.g. when you want to see if there is a newer Rails 2 version of your currently used gem.

At first you should search your gem at RubyGems. Example: will_paginate version history.

The "Tags" tab at GitHub might be helpful as well.

Git error: "badTimezone: invalid author/committer line - bad time zone"

You might get the above error message when cloning certain git repositories (for example the rails repository). It indicates that there is a malformed timestamp in some commit, and your git installation is configured to validate it.

As a workaround, you can disable the validation using

git config --global fetch.fsckobjects false

This settings seems to be the default for most git installations anyways.

RSpec: Change the type of a spec regardless of the folder it lives in

In a Rails application, *_spec.rb files get special treatment depending on the file's directory. E.g. when you put a spec in spec/controllers your examples will have some magic context like controller, post or get that appears out of nowhere.

If you want that magic context for a spec in another folder, use the :type option:

describe CakesController, :type => :controller do
  ...
end

Fixing "uninitialized constant ActiveSupport::Dependencies::Mutex (NameError)"

RubyGems 1.6.0 has undergone some changes which may cause Rails 2.x applications to break with an error like this one (e.g. when running script/server):
/usr/lib/ruby/gems/1.8/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:55: uninitialized constant ActiveSupport::Dependencies::Mutex (NameError)

Fix it by adding the following not only to your environment.rb but also into your script/server file, in both cases before boot.rb is required.
require 'thread'

If you still get the error above you can also add `require 'thre...

Inspecting model callback chains

If you need to look at the list of methods that are called upon certain events (like before/after saving etc), do this:

Model._save_callbacks.select {|cb| cb.kind == :before}.map{ |c| c.instance_variable_get :@filter }

Rails 2

User.after_save_callback_chain

To look at the method names only, you could do something like that:

User.after_save_callback_chain.collect(&:method)

Why your previous developer was terrible

When you, as a developer, look at the choices used to build a particular application, you’re blown away at the poor decisions made at every turn. “Why, oh why, is this built with Rails when Node.js would be so much better?” or “how could the previous developer not have forseen that the database would need referential integrity when they chose MongoDB?” But what you may not realize is that you are seeing the application as it exists today. When the previous developer (or team) had to develop it, they had to deal with a LOT of unknowns. They...

Recursively remove unnecessary executable-flags

Sometimes files attain executable-flags that they do not need, e.g. when your Windows VM copies them over a Samba share onto your machine.

From inside your Rails project directory call regularly:

geordi remove-executable-flags

Runs chmod -x on Ruby, HTML, CSS, image, Rake and similar files.


This script is part of our geordi gem on github.