671 snippets – displaying 1–30

Using Ruby 2.2.0 with Rails 3.x

rubyrailschristianVersion 4

Steps for upgrading a Rails 3.x app to Ruby 2.2.0:

  1. Install Ruby 2.2.0, e.g. brew update; brew upgrade ruby-build; rbenv install 2.2.0
  2. Set app’s ruby version to 2.2.0, e.g. rbenv local 2.2.0
  3. Update gems that are broken, e.g. bundle update pg eventmachine rubocop
  4. Add test-unit to Gemfile to fix “cannot load such file — test/unit/testcase (LoadError)” error:

gem 'test-unit'

  1. Rollback to 2.1 when you notice all warnings, related to e.g. Comparable, or continue with the warnings

JavaScript Promises With Q.js

This Q.js example calls two asynchronous methods in sequence:

class InitializeApp
  constructor: ->
    findDevice = ->
      df = Q.defer()
      onSuccess = (devices) ->
        console.log "Finding device"
        df.resolve("device 2")
      setTimeout(onSuccess, 2000)

    connectToDevice = (id) ->
      df = Q.defer()
      onSuccess = ->
        console.log "Connecting to #{id}"
      setTimeout(onSuccess, 2000)



new InitializeApp()
# ...Sleep 2 seconds
# => Finding device
# ...Sleep 2 seconds
# => Connecting to device 2

How to use Font Awesome in iOS/Phonegap apps

First, install Font Awesome:

  1. Download the latest Font Awesome version
  2. Double-click fontawesome-webfont.ttf and install it on your laptop/desktop (optional)
  3. Copy fontawesome.css to www/css
  4. Remove the references to font files in fontawesome.css, i.e. remove @font-face declaration

Then in Xcode:

  1. Copy fontawesome-webfont.ttf into “Your Project/Resources/fonts/fontawesome-webfont.ttf”
  2. Add Font Awesome to the .plist file by selecting the “Info” tab
  3. Add a new property named “Fonts provided by application” and set the value to “fontawesome-webfont.ttf”

Clean and build your project. Font Awesome is now ready to be used.

Phonegap example:

<i class="fa fa-cog"/>

How to hide the status bar in a Phonegap iOS app

To hide the status bar in a phonegap project:

  1. Double click on your project, or .plist, in XCode
  2. Select the tab named “Info”
  3. Add a new property by selecting an item in the list and then clicking the plus sign
  4. Name the property “View controller-based status bar appearance”
  5. Set the property value to “NO”


  1. Select the tab named general
  2. Check the “Hide status bar” located under “Deployment Info”


How to Open Safari's Web Inspector With Applescript to Debug a Phonegap App

This applescript will make Safari’s Web Inspector connect to a Phonegap application running on my iPhone that was started through XCode:


set device_name to "Christian Hellsten iPhone"
tell application "Safari"
	tell application "System Events"
			click menu item "index.html" of menu device_name of menu item device_name of menu "Utvecklare" of menu bar item "Utvecklare" of menu bar 1 of application process "Safari"
		end try
	end tell
end tell

Save the file, as e.g. open-web-inspector.applescript, then execute it:

chmod +x open-web-inspector.applescript

For English version, change “Utvecklare” to “Develop”.


  1. Error -1719 most likely means you need to enable assistive access for iTerm or whatever app you’re running the script from.
  1. Error -10810 means “bad luck” in Applescript. Try restarting the computer.

If all else fails, run the script using the Applescript Editor. Also see, this script.

Tested on OSX Yosemite.

CoffeeScript variable visibility

coffeescriptchristianVersion 3

This Coffeescript:

class Device
  x: 1 # Instance variable
  y = 2 # Private instance variable
  @z: 3 # Class variable

 # Address and name are instance variables
  constructor: (@address, @name) ->

gives us this JavaScript:

Device = (function() {
  var y;
  Device.prototype.x = 1;
  y = 2;
  function Device(address, name) {
    this.address = address;
    this.name = name;
  return Device;

and the following visibility:

dev = new Device('X', 'Y') # => Device {address: "X", name: "Y", x: 1}
dev.y # => undefined
Device.z # => 3

How to Debug Phonegap Applications With Safari's Remote Debugger

  1. On your iPhone/iPad: Enable Web Inspector . Open “Settings” → “Safari” → “Advanced”.
  2. On your desktop/laptop: Enable Developer tools in Safari. Open “Preferences” → “Advanced” check “Show Develop menu in menu bar”.
  3. Connect your iPhone via USB to your desktop/laptop.
  4. Start the application on your iPad/iPhone via XCode.
  5. On your desktop/laptop: Open the Safari Web Inspect debugger. Go to “Preferences” → “Your phone” → “index.html”.

You can automate the last step by using applescript to open Safari’s Web Inspector.

Note: Use CMD+R to reload index.html.

Phonegap Autorotate

In MainViewController#shouldAutorotateToInterfaceOrientation return YES:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
    // Return YES for supported orientations
    return YES; //[super shouldAutorotateToInterfaceOrientation:interfaceOrientation];

Running a Phonegap App in a Specific Version of iPhone


cordova emulate ios --target="iPhone-4s"
cordova emulate ios --target="iPad-Air"
cordova emulate ios --target="iPhone-6"
cordova emulate ios --target="iPhone-6-Plus"


phonegap run ios --target="iPhone-4s"
phonegap run ios --target="iPad-Air"
phonegap run ios --target="iPhone-6"
phonegap run ios --target="iPhone-6-Plus"

Gulpfile.js example with Slim, Coffeescript, Sass, Browser Sync, Lint

slimgulpchristianVersion 7

A Gulpfile.js example with Slim, Coffeescript, Sass, Browser Sync, Lint. The script is suitable for building e.g. static websites and prototyping mobile apps.

Gulpfile expects your project to be structured in the following way (configurable):
- src/css/.scss,.css
- src/js/.coffee,.js
- src/*.slim

Output is written to “www” folder.

# Gulpfile with:
# - Slim
# - Sass
# - Lint
# - Browsersync
# - CSS and HTML compression
# Install dependencies:
#   $ npm install gulp gulp-concat gulp-uglify event-stream gulp-coffee gulp-sass gulp-cssmin gulp-coffee gulp-coffeelint browser-sync gulp-util gulp-shell
# Then start developing:
#   $ gulp

gulp        = require 'gulp'
concat      = require 'gulp-concat'
es          = require('event-stream')
sass        = require 'gulp-sass'
uglify      = require 'gulp-uglify'
streamqueue = require 'streamqueue' # Preserves file order (vendor...)
coffee      = require 'gulp-coffee'
gutil       = require 'gulp-util'
shell       = require 'gulp-shell'
cssmin      = require 'gulp-cssmin'
coffeelint  = require 'gulp-coffeelint'
browserSync = require 'browser-sync'

isProd = gutil.env.type is 'prod'

sources =
  sass: 'src/css/**/*.scss'
  css: 'src/css/**/*.css'
  html: 'src/**/*.slim'
  js: 'src/js/**/*.js'
  coffee: 'src/js/**/*.coffee'

targets =
  css: 'www/css'
  html: 'www/'
  js: 'www/js'

# Check for errors
gulp.task 'lint', ->

# Compile Coffeescript
gulp.task 'js', ->
  stream = streamqueue(objectMode: true)
  # Vendor files
  # App files use Coffee
    .pipe(if isProd then uglify() else gutil.noop())

# Compile Slim
gulp.task 'slim', ->
    .pipe(shell(["slimrb -r ./lib/helpers.rb -p <%= file.path %> > ./#{targets.html}/<%= file.relative.replace(\".slim\", \".html\") %>"]))

# Compile CSS
gulp.task 'css', ->
  stream = streamqueue(objectMode: true)
  # Vendor files
  # App files
  stream.queue(gulp.src(sources.sass).pipe(sass(style: 'expanded', includePaths: ['src/css'], errLogToConsole: true)))
    .pipe(if isProd then uglify() else gutil.noop())

# Reload browser
gulp.task 'server', ->
  browserSync.init null,
    open: true
      baseDir: targets.html
    reloadDelay: 2000 # Prevent white screen of death
      debounceDelay: 1000

# Watch files for changes
gulp.task 'watch', ->
  gulp.watch sources.js, ['js']
  gulp.watch sources.css, ['css']
  gulp.watch sources.html, ['slim']
  gulp.watch 'www/**/**', (file) ->
    browserSync.reload(file.path) if file.type is "changed"

# Build everything
gulp.task 'build', ['lint', 'js', 'css', 'slim']

# Start a server and watch for file changes
gulp.task 'default', ['watch', 'server']

Writing a DSL in Ruby

rubydslchristianVersion 5

When defining a simple DSL instance_eval is your friend:

class Worker
  attr_reader :where
  def call(where, &block)
    @where = where
    instance_eval &block

  def cut_trees
    puts "Cutting trees"

  def make_planks
    puts "Making planks"

  def i(what, &block)
    instance_eval &block

def work where, &block
  puts "Working #{where}"
  Worker.new.(where, &block)
  puts "Going home"

Use the DSL like this:

work "in the woods" do
  i "take a coffee break" do
    puts "Cooking coffee #{where}"

Output is:

Working in the woods
Cutting trees
Making planks
Cooking coffee in the woods
Going home

Ruby's call method

rubycallchristianVersion 3

What does this print:

class RubyCall
  def call(*args)
    puts "Call: #{args}"

xxx = RubyCall.new
xxx.("hello", 1, 2, 3)

It calls the #call method and prints “Call: [”hello", 1, 2, 3]".

If you want to spice up your Ruby-life you can do this:


How to record and replay TCP traffic

tcpreplaychristianVersion 2

First attempt

1) Record TCP traffic with tcpdump to pcap file

Record traffic on ethic from host and port 2332, write to app-traffic.pcap:

tcpdump -vvv -i eth0 host and port 2332 -w app-traffic.pcap &

2) View captured traffic

tcpdump -qns 0 -X -r app-traffic.pcap

Edit captured traffic if needed with Wireshark.

3) Edit source IP so that it’s on your own network

See the ”example in tcprewrite documentation”:http://tcpreplay.synfin.net/wiki/tcprewrite for details on how to rewrite source IP:

$ tcprewrite --pnat=, --infile=input.pcap --outfile=output.pcap --skipbroadcast

4) Replay traffic with tcplivereplay from recorded pcap file (note step #3)

”See tcpliveplay documentation”:http://tcpreplay.synfin.net/wiki/tcpliveplay for details.

Note that tcpliveplay is only available on Linux not OSX.

Second attempt


sudo tcpdump -i en0 host and port 2332 -w app-traffic.pcap


tcpdump -s 0 -n -e -x -vvv -r app-traffic.pcap


sudo tcpreplay -i en0 -t -K app-traffic.pcap

Or use tcplivereplay (Note: Linux only):


I couldn’t get it to work….

Big Search Field & Button = Beautiful?

<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.css"/>

.search-form {
  width: 40%;
  min-width: 400px;
  border: 6px solid rgba(0, 0, 0, 0.7);
  margin: 20px auto 0;

input.text {
  float: left;
  width: 80%;
  border: 5px solid #fff;
  margin: 0;
  outline: none;
  font-size: 17px;
  -webkit-border-radius: 0;
  -moz-border-radius: 0;
  -ms-border-radius: 0;
  -o-border-radius: 0;
  border-radius: 0;
  -webkit-appearance: none;
  color: #3c3c3c;

input.text, input.button {
  padding: 15px;
  font-size: 17px;
  font-weight: 800;
  display: inline-block;
  -webkit-transition: all 0.3s ease;
  -moz-transition: all 0.3s ease;
  -o-transition: all 0.3s ease;
  transition: all 0.3s ease;

input.button {
  float: right;
  width: 20%;
  margin: 0;
  border: 5px solid grey;
  color: #fff;
  background-color: grey;
  -webkit-appearance: none;
  padding-left: 0;
  padding-right: 0;
  -webkit-border-radius: 0;
  -moz-border-radius: 0;
  -ms-border-radius: 0;
  -o-border-radius: 0;
  border-radius: 0;

.clearfix {
  overflow: auto;

* {
  font-family: "Helvetica", sans-serif;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;

  <div class="search-form clearfix">
    <input name="query" class="text" type="text" placeholder="Find your dog&hellip;">
    <input type="submit" value="Search" class="button">

Eventmachine Echo Server Example

require 'rubygems'
require 'eventmachine'
require 'logger'

# Each connection creates a new EchoServer.
module EchoServer
  LOG = Logger.new('echo.log')

  # Called by the event loop immediately after the network connection has been
  # established, and before resumption of the network loop.
  def post_init
    LOG.info "-- Connection established #{remote_ip} --"

  # Called by the event loop whenever data has been received by the network
  # connection. It is never called by user code.
  def receive_data data
    message = "#{remote_ip}: #{data}"
    LOG.info message
    send_data message
    close_connection if data =~ /quit/i

  # Called by the framework whenever a connection (either a server or client
  # connection) is closed.
  def unbind
    LOG.info "-- Connection closed #{remote_ip} --"

  # Return the IP and port of the remote client.
  def remote_ip
    @remote_ip ||= begin
                     port, ip = Socket.unpack_sockaddr_in(get_peername)

EventMachine::run do
  Signal.trap("INT")  { EventMachine.stop }
  Signal.trap("TERM") { EventMachine.stop }
  EventMachine::start_server "", 8080, EchoServer

Use telnet to test it:

$ telnet localhost 8080

Daemonization Best-Practices

Don’t daemonize your daemons


What’s the result? In development mode, your process will run in the foreground, as yourself and log to stdout: perfect for developers. In production mode, the init system will run your process as a configured user with logging sent to a specific location and log rotated automatically. Less system administration, easier debugging, simpler code, all because you leveraged the init system to do the work for you!</quote>

Running processes


Note: In every case, it’s assumed that you have a program that wants to run that does not daemonize on its own. Self-daemonizing programs start you down the path to hell. You can’t use any sane keepalive techniques so you have to resort to polling process lists or checking the pid or something. Even managing that pidfile gets hard when you combine it with things that change their own uid for safety (because you should never run anything as root).</quote>

Ubuntu, upstart, and creating a pid for monitoring


If start-stop-daemon is available on your machine, I would highly recommend using it to launch your process. start-stop-daemon will handle launching the process as an unprivileged user without forking from sudo or su (recommended in the upstart cookbook) AND it also has built in support for pid file management.</quote>



Foreman is a manager for Procfile-based applications. Its aim is to abstract away the details of the Procfile format, and allow you to either run your application directly or export it to some other process management format.</quote>

How to introduce Rubocop in your project


Edit Gemfile:

group :development do
  gem 'rubocop' # Style guide checker
  gem 'guard-rubocop' # Rubocop plugin for Guard


$ bundle


Run Rubocop:

$ rubocop --auto-gen-config


Edit .rubocop.yml:

inherit_from: .rubocop_todo.yml

Introduce new rules gradually in priority order by enabling and moving rules from .rubocop_todo.yml to .rubocop.yml.

You can also use the Ruby style-guide’s rubocop configuration:

Workflow integration


$ guard init rubocop

Edit Guardfile:

guard :rubocop, all_on_start: false, cli: ['--format', 'clang', '--rails'] do
  watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }

Editor Integration

Optionally, integrate Rubocop with your editor:

CI integration

See How to introduce rubocop and integrate into Jenkins.

How to parse a cronline/crontab/cron with Ruby

You can use the rufus-scheduler gem to parse cronline/crontab/cron with Ruby.


gem 'rufus-scheduler'


require 'rufus/scheduler/cronline'
cron = Rufus::Scheduler::CronLine.new("00 00 1 * *") # 00:00 every first day of the month
next_time = cron.next_time(Time.current)
previous_time = cron.previous_time(Time.current)

rufus-scheduler’s cronline implementation:

See tests for details and syntax:

Cron configuration examples.

Playing with Ruby and Rails Time and Time Zones


What you need to know to handle date and time correctly in Ruby and Rails is, at least:

  • the input’s time zone when parsing time and date.
  • the user’s time zone when calculating time and date in his/her time zone.
  • Ruby and Rails date and time handling. Use Time.current and Time.zone (Rails) to avoid using the computer’s time zone (Ruby).

Things to remember

  • Is the given time in the user’s time zone (Time.zone.local) or in UTC (Time.zone.utc)?
  • The correct time zone is needed when you’re accessing date components like e.g. year, month, day, hour, start of day, start of month, etc
  • Rails takes care of time and date handling inside the application. It’s when you accept input or want to output data that you need to tread carefully.
  • Cache carefully. Maybe you need to display date and time using JavaScripts.
  • Daylight savings, plus some countries or states don’t even have DST, but might have had 100 years ago…
  • The difference between e.g. Time.now and Time.current.
  • Possible timezones: application, user, server, and database timezone
  • APIs should output ISO-8601

require 'tzinfo'
tokyo = TZInfo::Timezone.get('Asia/Tokyo')

# When it's 12:00 in Tokyo, what hour is it in UTC?
time = tokyo.local_to_utc Time.local(2014, 01, 01, 12, 00) # => 2014-01-01 03:00:00 UTC
utc_hour = time.hour # => 3
utc_time = time.utc # => 2014-01-01 03:00:00 UTC

# When it's 12:00 in UTC, what hour is it in Tokyo?
time = tokyo.utc_to_local Time.local(2014, 01, 01, 12, 00) # => 2014-01-01 21:00:00 UTC
tokyo_hour = time.hour # => 21
tokyo_time = tokyo.local_to_utc(time) # => 2014-01-01 12:00:00 UTC

# Convert Tokyo time to local time, i.e. convert user's local time to our local time
tokyo.now # => Tue, 18 Nov 2014 03:02:28 JST +09:00
tokyo.now.utc # => 2014-11-17 18:04:20 UTC
# local_to_utc => -0900
tokyo.local_to_utc tokyo.now # => 2014-11-17 18:03:02 UTC
# utc_to_local => +0900
tokyo.utc_to_local tokyo.now # => 2014-11-18 12:03:17 UTC
Time.parse Time.find_zone!('Tokyo').now.to_s

# Parse input from Helsinki and input from Stockholm when input contains no time zone information
a = Time.find_zone!('Helsinki').parse('201411121415')
b = Time.find_zone!('Stockholm').parse('201411121315')
a == b

a = Time.use_zone 'Helsinki' do
b = Time.use_zone 'Stockholm' do
a == b # OK

# Using the tzinfo library directly
zone = TZInfo::Timezone.get('Africa/Harare')

# Rails time zones

# Daylight savings, anyone?
tokyo = TZInfo::Timezone.get('Asia/Tokyo')
tokyo.current_period.utc_offset # Doesn't include DST
tokyo.current_period.utc_total_offset # Includes DST

Time.use_zone 'Helsinki' do
  Time.local(2014, 10, 26).dst? # => true
  Time.local(2014, 10, 27).dst? # => false

Time.use_zone 'Pacific Time (US & Canada)' do
  # 00:00 01.06.2014 in Los Angeles, during DST
  now = Time.zone.local(2014, 6, 1)
  puts now.dst? # => true
  offset = now.utc_offset
  puts offset / 1.hour # => -7
  # 00:00 01.12.2014 in Los Angeles, after DST
  now = Time.zone.local(2014, 12, 1)
  puts now.dst? # => false
  offset = now.utc_offset
  puts offset / 1.hour # => -8

# Beginning of day in other time zone
Time.use_zone 'Hawaii' do
  now = Time.local(2014, 10, 27)
  puts now.beginning_of_day.dst? # false, Hawaii doesn't follow DST although the rest of the U.S.A. does.
  puts now.beginning_of_day.utc # => 2014-10-26 22:00:00 UTC
  puts now.beginning_of_day # => 2014-10-27 00:00:00 +0200

# Misc stuff

Time.now.formatted_offset # => "+02:00"

def without_timezone
  times = [

  times.each do |time|
    puts times[0].to_i == time.to_i # All OK

def with_timezone
  times = nil
  Time.use_zone('Tokyo') do
    times = [
  Time.use_zone('Stockholm') do
    times.each do |time|
      puts times[0].to_i == time.to_i # All OK

def parse_time
  times = nil
  time = '201411121415'
  Time.use_zone('Tokyo') do
    times = [
      Time.zone.parse(time).in_time_zone, # ERROR: 7 hour time difference
      Time.zone.parse(time) # ERROR: 7 hour time difference
  Time.use_zone('Stockholm') do
    times.each do |time|
      binding.pry unless times[0].to_i == time.to_i


Also see Working with time zones in Ruby on Rails.

How to run only one specific test with Rspec

Focusing on one or more tests with Rspec

You can tell Rspec to run only tests tagged with “focus: true” by running Rspec with the —tag focus switch:

rspec ./spec/controllers/concerns/session_expiry_spec.rb --tag focus

This would run e.g. only this test which is marked with “focus: true”:

it "resets session if session has expired", focus: true do

Integrating with Guard

Use this configuration to integrate this workflow with Guard:

guard 'rspec', cli: '--tag focus --format d --color', all_after_pass: false, all_on_start: false do

We also want to run all tests when there are no focused tests. We therefore add this to spec/spec_helper.rb:

RSpec.configure do |config|
  # This is dangerous with CI integration e.g. Jenkins
  # config.filter_run focus: true
  config.run_all_when_everything_filtered = true

Rspec configuration file

One alternative is to enable the focus option in the Rspec configuration file:

RSpec.configure do |config|
  config.filter_run :focus => true
  config.run_all_when_everything_filtered = true

However, this would be dangerous when running tests with e.g. Jenkins and when someone forgets to remove “focus: true”.

I18n for ActiveRecord Model Attributes

This code will translate the AR model’s title attribute using Rails’ I18n library:

class Link < ActiveRecord::Base
  I18N_ATTRIBUTES = [ :title ]
  I18N_ATTRIBUTES.each do |attr|
    class_eval <<-EORUBY, __FILE__, __LINE__ + 1
      def #{attr}
        I18n.t(self[:#{attr}], default: self[:#{attr}])

If a translation is not defined, the code will fall back to use the attribute’s original value.

Example with translation defined:

Translation file (config/locales/en.yml):

      title: Hello

Model code (app/models/link.rb):

link.title = 'views.index.title'
# Uses string from config/locales/en.yml
link.title => "Hello"

Example without translation defined

link = Link.new title: 'Hello'
# Fall back to specified value, because no translation is defined
link.title => "Hello"

How to draw centered text on an HTML canvas

Draw centered text on an HTML canvas:

canvas = ...
// Device dependent pixel ratio, also changes when zooming
pixelRatio = window.devicePixelRatio || 1
// Centered text
ctx.textAlign = "center"
ctx.textBaseline = "middle"
// Font size
fontSize = 20
// Adaptive bold font
ctx.font = 'bold ' + Math.round(fontSize/pixelRatio) + 'px Oswald'
// Measure text width
textRect = ctx.measureText(text)
// Figure out where to position the text
x = (canvas.width / 2) / pixelRatio
y = ((canvas.height / 2) - (fontSize*2)) / pixelRatio
// Draw the text
ctx.fillText("Hello world" , x, y)

The code adapts the font size and text position to fit the selected zoom level (e.g. 200%) and the current device (e.g. mobile).

How to Use the JSON and HStore Postgres Data Types With Rails 4

First enable the hstore Postgres extension. In this example we define both a JSON and an HStore column:

class Schema < ActiveRecord::Migration
  def change
    enable_extension "hstore"
    create_table :links do |t|
      t.hstore :data
      t.column :settings, :json

Next, we specify accessors for the data that we will be stored in the JSON and HStore columns:

class Link < ActiveRecord::Base
  # Use hstore for text-only data:
  store :data, :name, :url, :description
  # Use JSON to support string, number, object, array, true, false, null
  store :settings, :update_interval, :created_at, :updated_at

We can now use the defined ActiveRecord attributes to store and access JSON and HStore data:

Link.create! name: 'Google', url: 'http://google.com', description: 'Ad company', update_interval: 1.day, created_at: Time.now.utc

Querying the data is where you’ll see the biggest differences. Two examples:

# hstore
Link.where("data -> 'name' = ?", 'Google')
# json
Link.where("CAST(settings->>'update_interval' as integer) = ?", 1.day.to_s)

Notes for Postgres 9.3:

  • HStore can store only text. Nested data is not supported.
  • JSON supports the following types: string, number, object, array, true, false, null. For example, date and time types are not supported. Nested data is supported.

Rails prepend_view_path


class ApplicationController < ActionController::Base
  prepend_view_path 'x/y/z/views'


# config/initializer/view_path.rb
ApplicationController.prepend_view_path 'x/y/z/views'

In development mode (Rails 3.x) this doesn’t seem to work under some circumstances, i.e. the prepended path is lost after Rails’ reloads after you modify certain files.

How to Use Rails I18n With JavaScript/CoffeeScript

Option 1: Include all translations

Your app/assets/javascripts/i18n.js.coffee.erb file:

root = exports ? this
I18n = <%= I18n.backend.send(:translations).to_json.html_safe %>
$ ->
  root.I18n = I18n[$('body').data('lang')]

Option 2: Include a limited set of translations

Your app/assets/javascripts/i18n.js.coffee.erb file:

root = exports ? this

I18n =
I18n.available_locales.each do |lang|
  I18n.with_locale lang do
  <%= lang %>:
    text: "<%= I18n.t("js.text") %>"

$ ->
  root.I18n = I18n[$('body').data('lang')]

Include the Selected Locale in the Rails Layout

The view defines the user’s selected locale:

<body data-lang="<%= I18n.locale %>">

How to Translate JavaScript Strings

We can now translate strings in a JavaScript file:

# remember to use $(document).ready...