How to deal with MethodNotAllowed errors

One of the most common production errors are ActionController::MethodNotAllowed errors. They usually happen when someone reloads a form by pressing enter/return in the URL field, or by opening JavaScript links incorrectly.

The attached initializer provides a default way to deal with this.

You'll get the following behaviour:

  • if the incorrect request has a HTTP_REFERER coming from the same application, set a flash, and redirect back
  • if the incorrect request has no HTTP_REFERER or one coming from an external source, set a flash...

Embed Google Analytics code for some environments only

When you use google analytics to track your visitors interactions, you should ensure that it runs on your production site only. Otherwise it will spoil your statistics. To prevent this, test for the right environment and place the JS-code afterwards:

- if Rails.env.production?
  :javascript
    var _gaq = _gaq || [];
    _gaq.push(['_setAccount', 'UA-XXXXXXXX-X']);
    _gaq.push(['_trackPageview']);
    ...

jQuery 1.7 Released

Two new methods on and off are the new way of declaring event handlers. bind, delegate and live area deprecated. Also better performance for delegated events.

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
  )

...

Rails 3.1 error message: Could not find a JavaScript runtime

After starting the Rails server in a freshly generated Rails 3.1 project you could see an error message such as

/usr/lib/ruby/gems/1.8/gems/execjs-1.3.0/lib/execjs/runtimes.rb:50:in `autodetect': Could not find a JavaScript runtime. See https://github.com/sstephenson/execjs for a list of available runtimes. (ExecJS::RuntimeUnavailable)

Just add a JavaScript runtime to your Gemfile and the error vanishes.

Examples:

gem 'therubyracer'
gem 'extjs'

Fix multiple CKEditor instances using jQuery adapter - fixed since 4.2

Using the jQuery adapter breaks the built-in save function of CKEditor.

Phenomenon: The page is submitted correctly, but the original values of the form fields were posted instead of what was typed in the editors.

Work around: Basicly instead of initiating the editor using the above example I ended up using the following:

$( 'textarea.editor').each( function() {

    CKEDITOR.replace( $(this).attr('id') );

});

Note: This assumes that each field using the editor has its own unique ID.

Parse & sort unique hits in logfiles

If you want to know the exact hits on your website (or whatever logfile you want) for a specific date without duplicates, here's how.
"Unique" means you don't want to count hits to an URL originating from the same IP twice.

You can use the attached script to do so:

# ./log_parser.rb 2011-10-04

27 hits on /rss.xml
36 hits on /stylesheets/fonts/slkscr-webfont.woff
37 hits on /stylesheets/fonts/slkscrb-webfont.woff
37 hits on /images/bullet.png
38 hits on /images/download.png
38 hits on /images/play.png
39...

Javascript equivalent of Ruby's array.collect(&:method)

The most common use case for Ruby's #collect is to call a method on each list element and collect the return values in a new array:

['hello', 'world', 'this', 'is', 'nice'].collect(&:length)
# => [5, 5, 4, 2, 4]

Although there is no equivalent to this idiom in naked Javascript, there is a way to collect object properties (but not method results) if you are using common Javascript libraries.

If you are using jQuery with the Underscore.js utility library, you can use [pluck](htt...

Single step and slow motion for cucumber scenarios using @javascript selenium

Single step and slow motion for Cucumber scenarios can come in handy, especially in @javascript scenarios.

# features/support/examiners.rb
AfterStep('@slow_motion') do
  sleep 2
end

AfterStep('@single_step') do
  print "Single Stepping. Hit enter to continue"
  STDIN.getc
end

If you're using spreewald, these tags are available as @slow-motion and @single-step (with dashes instead of underscores).

Note: You can also [prevent the selenium webbrowser wind...

Prevent the selenium webbrowser window from closing after a failed @javascript step

When cucumber encounters a failing step in a @javascript feature, the selenium browser window instantly closes. Sometimes you do not want that, because you need to see what is going on. You can click through the data your feature created, when you add the following file to your features/support directory:

#features/support/examiners.rb

After('@leave_the_window_open') do |scenario|
  if scenario.respond_to?(:status) && scenario.status == :failed
    print "Step Failed. Press return to close browser"
    STDIN.getc
  ...

sstephenson/execjs - GitHub

ExecJS lets you run JavaScript code from Ruby. It automatically picks the best runtime available to evaluate your JavaScript program, then returns the result to you as a Ruby object.

How to accept or deny JavaScript confirmation dialogs in Capybara/Selenium

These methods are available to you:

page.driver.browser.switch_to.alert.accept
page.driver.browser.switch_to.alert.dismiss
page.driver.browser.switch_to.alert.text # the confirmation text

Spreewald gives you steps like these:

When I confirm the browser dialog
When I cancel the browser dialog

Note that recent versions of Selenium will automatically dismiss confirmation dialogs. [Here is how to fix that](https://makandracards.com/makandra/617366-configure-selenium-webdriv...

Rails 3.1.0 has been released!

jQuery as new default Javascript library, streaming response support, attr_accessible with roles, prepared statements, easier migrations.

Detect the current Rails environment from JavaScript or CSS

Detecting if a Javascript is running under Selenium WebDriver is super-painful. It's much easier to detect the current Rails environment instead.

You might be better of checking against the name of the current Rails environment. To do this, store the environment name in a data-environment of your <html>. E.g., in your application layout:

<html data-environment=<%= Rails.env %>>

Now you can say in a pi...

Chosen - makes select boxes better

Chosen is a JavaScript plugin that makes long, unwieldy select boxes much more user-friendly. It is currently available in both jQuery and Prototype flavors.

JSONP - Wikipedia

Under the same origin policy, a web page served from server1.example.com cannot normally connect to or communicate with a server other than server1.example.com. An exception is the HTML <script> element. Taking advantage of the open policy for <script> elements, some pages use them to retrieve Javascript code that operates on dynamically-generated JSON-formatted data from other origins. This usage pattern is known as JSONP. Requests for JSONP retrieve not JSON, but arbitrary JavaScript code.

Cross-Origin Resource Sharing - Wikipedia

Cross-Origin Resource Sharing (CORS) is a browser technology specification, which defines ways for a web service to provide interfaces for sandboxed scripts coming from a different domain under same origin policy. CORS is a modern alternative to the JSONP pattern. While JSONP supports only the GET request method, CORS also supports other types of HTTP requests. Using CORS enables a web programmer to use regular XMLHttpRequest which supports better error handling than JSONP. On the other hand, JSONP works on legacy browsers that do not have C...

simple_format helper for Javascript

The Javascript code below is a rough equivalent to the simple_format helper that ships with Rails:

function simpleFormat(str) {
  str = str.replace(/\r\n?/, "\n");
  str = $.trim(str);
  if (str.length > 0) {
    str = str.replace(/\n\n+/g, '</p><p>');
    str = str.replace(/\n/g, '<br />');
    str = '<p>' + str + '</p>';
  }
  return str;
}

Unlike the Rails helper, this does not preserve whitespace. You probably don't care.

How to hide your selenium browser window with "headless"

Note: While the solution in this card should still work, we prefer another solution now: Hide your Selenium browser window with a VNC server.


If you would like to hide the annoying selenium browser window that always gets the focus and prevents you from working, you can use the headless gem. This note provides some instructions how you can get it to work with your cucumber accepta...

Rails 3: Make "link_to :remote => true" replace HTML elements with jQuery

In Rails 2, you could use link_to_remote ... :update => 'id' to automatically replace the content of $('#id').

To do the same in Rails 3, include usual rails-ujs JavaScript, and put this into your application.js:

$(function() {
  $('[data-remote][data-replace]')
    .data('type', 'html')
    .live('ajax:success', function(event, data) {
      var $this = $(this);
      $($this.data('replace')).html(data);
      $this.trigger('ajax:replaced');...

Failtale

Free Hoptoad/Airbrake alternative which can capture exceptions from any platform. It comes with a Rails notifier and a RESTful API to write your own notifiers for Javascript, etc.

Should we some day wish to do away with the current way we deal with exceptions, this might be a good place to start.

Disable text selection on iOS and Android devices

When you double-tap a string of text on an iPhone or iPad a complicated context menu for copying and pasting will appear. This can confuse unexperienced users.

Use the Javascript hack below to disable text selection on mobile devices:

// Deactivating distracting Text Selection:
// from: http://stackoverflow.com/questions/1794220/how-to-disable-mobilesafari-auto-selection
$.fn.extend({
  disableSelection : function() {
    this.each(function() {
      this.onselectstart = function() {
        return false;
  ...

Popular mistakes when using nested forms

Here are some popular mistakes when using nested forms:

  • You are using fields_for instead of form.fields_for.
  • You forgot to use accepts_nested_attributes in the containing model. Rails won't complain, but nothing will work. In particular, nested_form.object will be nil.
  • The :reject_if option lambda in your accepts_nested_attributes call is defined incorrectly. Raise the attributes hash given to your :reject_if lambda to see if it looks like you expect.
  • If you are nesting forms into nested forms, each model involved ne...

Check whether an element is visible or hidden with Javascript

jQuery

You can say:

$(element).is(':visible')

and

$(element).is(':hidden')

jQuery considers an element to be visible if it consumes space in the document. For most purposes, this is exactly what you want.

Native DOM API

Emulate jQuery's implementation :

element.offsetWidth > 0 && element.offsetHeight > 0;

jQuery > 3

Query 3 slightly modifies the meaning of :visible (and therefore of :hidden).

Emulate jQuery'...