Live through coding

by Jorge Kalmbach

jQuery Clock Plugin

| Comments

jquery.clock.js is a little jQuery plugin to show a real time clock.

It prints out something like this:

1
Thu, 25 Apr 2013 02:19:53 UTC

[download | github]

Usage

Include the javascript:

1
<script type="text/javascript" src="path_to/jquery.clock.js"></script>

Include an element where to show the clock, for example:

1
<span id="my-clock"></span>

Call the function in the elements you want to show the clock, like the span we added before:

1
$('#my-clock').clock();

Pass some options (details below)

1
$('#my-clock').clock({ utc: false });

Options

It has only three options:

1
{ utc: true, utc_label: true, interval: 500 }
  • utc. If true shows an UTC clock, if false shows a locale clock. Default is true.

  • utc_label. If true replaces the GMT label with the UTC label. Default is true.

  • interval. Miliseconds interval to update the clock. Default is 500.

Rack Middleware for Flash Messages

| Comments

The flash is a special part of the session which is cleared with each request. This means that values stored there will only be available for the request, which is useful for storing error messages, notices, etc.

Note: this does not work for redirect requests. If you set a flash message and then you redirect to another path, the flash hash will be cleared first and then the redirect request will happen, with a clean flash hash.

usage:

1
2
3
use Rack::Session::Flash

env['rack.session']['flash'][:error] = 'Something bad just happened.'

If you are using Cuba, you can do:

1
2
3
Cuba.use Rack::Session::Flash

session['flash'][:error] = 'Something bad just happened.'

or even better, you can create a plugin

1
2
3
4
5
6
7
8
9
10
module FlashHelper
  def flash
    session['flash']
  end
end

Cuba.use Rack::Session::Flash
Cuba.plugin FlashHelper

flash[:error] = "Something bad just happened."

Here is the implementation of the rack middleware.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
module Rack
  module Session
    class Flash
      def initialize(app)
        @app = app
      end

      def call(env)
        dup.call!(env)
      end

      def call!(env)
        env['rack.session'] || raise(RuntimeError,
          'You\'re missing a session handler. ' +
          'You can get started using Rack::Session::Cookie')

        env['rack.session']['flash'] ||= {}

        response = @app.call(env)

        env['rack.session']['flash'].clear

        response
      end
    end
  end
end

Cuba Asset Pipeline

| Comments

Cuba: is a Ruby microframework for web development.
Sprockets: is a Ruby library for compiling and serving web assets.

If you never heard of sprockets before you should know that is the heart of the Rails Asset Pipeline. We can also use it outside of rails to build an asset pipeline for our Cuba applications. We will need an instance of the Sprockets::Environment class to access and serve assets from our application. The Sprockets Environment has methods for retrieving and serving assets, manipulating the load path, and registering processors. It is also a Rack application that can be mounted at a URL to serve assets over HTTP, we will do this in our config.ru file.

1
2
3
4
5
6
7
8
9
10
11
require File.expand_path("app", File.dirname(__FILE__))
require 'sprockets'

map '/assets' do
  env = Sprockets::Environment.new
  run env
end

map '/' do
  run Cuba
end

After creating the sprockets environment we need to configure the paths from where we will be serving the assets. For example if you have the following folder structure in your project:

1
2
3
4
 assets
   - javascripts
   - stylesheets
   - images

To configure the paths we append them to the sprockets environment we instantiated:

1
2
3
  env.append_path 'assets/javascripts'
  env.append_path 'assets/stylesheets'
  env.append_path 'assets/images'

Then you need to use the right path in your view references:

1
2
<script src="/assets/application.js"></script>
<link rel="stylesheet" href="/assets/application.css">

Here is a full sample using the Yui Compressor for compressing the stylesheets and the javascripts. I am also using memcache to cache the assets to avoid resending them to the client browser if they had not changed.

config.ru

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
require File.expand_path("app", File.dirname(__FILE__))
require 'yui/compressor'
require 'sprockets'
require 'dalli'

# GZip compession
use Rack::Deflater

map '/assets' do
  env = Sprockets::Environment.new
  env.append_path 'assets/javascripts'
  env.append_path 'assets/stylesheets'
  env.append_path 'assets/images'

  # use MemCache
  env.cache = Dalli::Client.new('localhost:11211')

  # Compress assets
  env.js_compressor  = YUI::JavaScriptCompressor.new
  env.css_compressor = YUI::CssCompressor.new

  run env
end

map '/' do
  run Cuba
end

Serve Coffeescript on Cuba

| Comments

Cuba: is a Ruby microframework for web development.
CoffeeScript: is a little language that compiles into JavaScript.

Now that we have set the basics, we can continue with the topic that bring us here today. In order to serve coffeescript as compiled javascript we will need to use the Rack::Coffee middleware.

In your Cuba app, this is as easy as doing the following:

1
2
3
4
require "rack/coffee"

# Search the coffeescript files int /public/coffee
Cuba.use Rack::Coffee, root: "public", urls: ["/coffee"]

Then you just need to include the coffeescript file in your view, you will need to replace the .coffee extension with .js.

1
2
<!-- This will serve /public/coffee/script.coffee -->
<script src="/public/coffee/script.js"></script>

Troubleshooting

If you are using the Rack::Static middleware, you will need to serve your coffeescript files from a different location.

1
2
Cuba.use Rack::Static, root: "public", urls: ["/javascript"]
Cuba.use Rack::Coffee, root: "public", urls: ["/coffee"]

Demo

I wrote a little demo, you can watch it on cuba-coffee.herokuapp.com, you can also review the code for that demo in github

Rack::Coffee

The Rack::Coffee middleware has other configuration values worth to check:

cache-compile: When truthy, will create and look for tempfiles with the timestamp of the desired coffee file, and use those.

cache-control: Sets a Cache-Control header if present. Defaults to false. Values are interpreted like so:

1
2
3
4
5
true: max-age=86400
3600: max-age=3600
:public or 'public': max-age=86400, public
[3600, :public] or %w(3600 public): max-age=3600, public
false or nil: disables cache header

join Set to a string, f.e. “index” to concat all the .coffee files before compiling.

Configuring New Relic in Heroku for a Cuba Application

| Comments

First you need to check the heroku’s help on installing and configuring New Relic from a (not Rails) Rack app, like Sinatra or Cuba.

New Relic from a Cuba App

  1. Install the add-on in the heroku app:

    heroku addons:add newrelic:standard

  2. Add the gem to your Gemfile (and run bundle install)

    gem 'newrelic_rpm'

  3. Make sure(1) you have a RACK_ENV config var in your application, if not, you can add one

    heroku config:add RACK_ENV=production

  4. Copy this file newrelic.yml into config/newrelic.yml

  5. Assuming your main application file is app.rb, add this to your file:

1
2
3
4
if ENV['RACK_ENV'] == 'production'
  require 'newrelic_rpm'
  ::NewRelic::Agent.manual_start :app_name => 'your-application-name'
end

The ruby agent will not start by himself, so you need to force it.

The :app_name is the same one as in the NEW_RELIC_APP_NAME config var.

(1) To see the config vars run heroku config.

Execute Model Hook in Separate Thread

| Comments

Today I had a situation where I had to translate a geopoint (latitude, longitude) into a physical address, commonly called reverse geocode. Think on a Place model, where each new record have a latitude and longitude, and you need to resolve that geopoint into a real world address and save it on the record.

For the reverse geocode part I used the OpenStreetMap Nominatim service, with the osmn ruby gem.

I first had a before_save model hook to set the address, doing a reverse geocode of the latitude and longitude using the osmn library, but, as you can imagine, I had to wait for the nominatim service to respond to be able to save the record. The process was taking to much time, and I actually didn’t need the address value right away after creating the record.

Moving it to an after_create model hook didn’t work neiter because the code still waits for all the hooks to end before returning. I first thought that I would need delayed_job or some kind of background worker that could do the reverse geocode in the background after creating the record, but I didn’t had anything of that in the project and it sounded as an overkill solution.

Then I thought of Threads. A simple and plain thread will be the perfect solution in this case. Inside the after_create method I created a Thread with the reverse geocode call. That way I can create the record, and continue processing new records while the reverse geocode is ocurring in a separated thread.

1
2
3
4
5
6
7
8
9
10
11
12
require "osmn"

class Place < Sequel::Model
  def reverse_geocode!
    self.address = OSMN::reverse_geocode(latitude, longitude).display_name
    save
  end

  def after_create
    Thread.new { reverse_geocode! }
  end
end

Ruby Threads documentation

Encrypting Data With OpenSSL and Ruby (III)

| Comments

Ok, we saw public-key (or asymmetric) and symmetric-key cryptography. With the first one you have a pair of keys, one of which is public and you can share with your friends in order to exchange info, they can encrypt the data using your public key and only you will be able to decrypt it. Also you can encrypt (sign in) something with your private key, and that can only be decrypt using your public key, which ensures the data came from you (that’s why is called signature).

So, if you encrypts the data with your private-key, and then with your friend’s public key, you will have a safe channel, the data will be signed by you and only your friend will be able to see it. Unfortunately this can only be used with small amounts of data (limited by the size of the key).

On the other side, we have the symmetric-key encryption, that can encrypt large amounts of data without problem, but we cannot send the secret-key by email to our friends, since it could be intercepted or revealed and all will be able to decrypt the data. If only there was a way to share this small secret-key with your friend… oh wait.

Yes! we can combine both methods to share information. (Pretty Good Privacy)

Using the public-key encryption to share our symmetric-key, and then the symmetric-key to encrypt the data. Finally you send the encrypted data with the encrypted and signed symmetric key.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
require 'openssl'

# This is our secret
data = File.read('a-lot-of-secrets.txt')

# Create a RSA key (public-key) of 2048 bits
rsa_key = OpenSSL::PKey::RSA.new (2048)

# Extract the public key
public_key = rsa_key.public_key.export

# Send my public key to my friend
# Get his public key and store it
friend_key = share_public_key(public_key)

# Create AES cipher, (symmetric-key) of 128 bits
aes_cipher = OpenSSL::Cipher::AES.new(128, 'CBC')
aes_cipher.encrypt
key = aes_cipher.random_key
iv  = aes_cipher.random_iv

# sign the key
signed_key = rsa_key.private_encrypt(key)
signed_iv  = rsa_key.private_encrypt(iv)

# encrypt keys with friend's key
friends_rsa_key = OpenSSL::PKey::RSA.new(friend_key)
encrypted_key = friends_rsa_key.public_encrypt(signed_key)
encrypted_iv  = friends_rsa_key.public_encrypt(signed_iv)

# send to friend the encrypted_key + encrypted_iv
# He will decrypt first with his private key, and then with our public key.

# now that we securely shared the symmetric key encryption, 
# we can send him the encrypted data
encrypted_data = aes_cipher.update(data) + aes_cipher.final

Encrypting Data With OpenSSL and Ruby (II)

| Comments

We already saw how to encrypt small amounts of data, like credit cards, web forms or signatures with public-key encryption. Today we will see how to encrypt large amounts of data using symmetric-key encryption.

Symmetric-key algorithms are a class of algorithms for cryptography that use the same cryptographic key for both operations, encryption and decryption of data, for this reason the key must remain secret.

OpenSSL supports a large variety of symmetric-key algorithms, a list of the supported algorithms can be obtained with:

1
OpenSSL::Cipher.ciphers

To create a Cipher instance you need to know 3 things, the name of the algorithm, the length of the key in bits and the cipher mode to be used. The most generic way to create a new Cipher object is like this:

1
2
3
4
5
name = 'AES'
bits = '128'
mode = 'CBC'

cipher = OpenSSL::Cipher.new("#{name}-#{bits}-#{mode}")

The string parameter must be all in uppercase or all in lowercase. Each algorithm has also a class defined under the Cipher namespace that you can use to obtain an instance of that algorithm:

1
cipher = OpenSSL::Cipher::AES.new(128, 'CBC')

For symmetric algorithms, encryption and decryption are very similar operations, and you can do both with your Cipher instance. However you need to set the instance with the operation you intend to do with it. This is done calling encrypt or decrypt on the instance without parameters:

1
2
3
4
5
cipher = OpenSSL::Cipher::AES.new(128, 'CBC')
cipher.encrypt

decipher = OpenSSL::Cipher::AES.new(128, 'CBC')
decipher.decrypt

After obtaining the instance of the Cipher and setting the operation, we need to set the key to be used. The cipher instance provides a way to generate a random and more secure key than a plain and simple password. The cipher modes CBC, CFB, OFB and CTR all need an initialization vector, IV for short, if not explicity set, OpenSSL will default the IV to all-zeroez. The cipher instance also provides a way to create a secure random IV. In brief, you will need a key and an initialization vector:

1
2
3
4
5
cipher = OpenSSL::Cipher::AES.new(128, 'CBC')
cipher.encrypt

key = cipher.random_key
iv  = cipher.random_iv

Warning

ECB and CBC are both block-based modes, unlike the streaming-based modes, they
operate on fixed-size blocks of data, and therefore they require a finalization
(padding) to decrypt the last block of data. For that reason you need to add the
content of #final to the encryption/decryption buffer or you will end up with
errors or truncated data.

Finally, all said, we can encrypt and decrypt some data:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
plain_data = "My secret is that there is no secret"
cipher = OpenSSL::Cipher::AES.new(128, 'CBC')

cipher.encrypt
key = cipher.random_key
iv  = cipher.random_iv

encrypted_data = cipher.update(plain_data) + cipher.final

cipher.decrypt
cipher.key = key
cipher.iv = iv

plain_data = cipher.update(encrypted_data) + cipher.final

Encrypting Data With OpenSSL and Ruby

| Comments

Hi, today’s tip is about protecting data with encryption, we will use public-key cryptography, this allow us to encrypt data using a key public, that you can give your friends or to your mother or to your clients. They can encrypt the data that they want to send you or you want to keep secure, and only you can decrypt it with your private key, the private key must remain in secret to yourself and you can protect it with a passphrase.

Warning

The method that will be described here only allows the encryption of a small
amount of data. To be precise, you cannot encrypt anything larger than the key
size minus 11 bytes of padding. If you will use a 2048 bit key size, you will be
able to encrypt upto (2048 bits / 8) bytes – 11 bytes = 245 bytes of data.

You can use this, for example, to encrypt data in a web form, and store them secured. So you can provide the client side with a public key, and later only you will be able to retrieve or decrypt that data on the server side using the private key. This can be usefull to capture and send sensitive data through the internet.

Ok, to do this, we first need to generate our keys. We will use openssl because I had a bad experience using gpgme on ruby, especially when I needed it to encrypt a large number of items, the gpg context was crashing without any explanation. I reported the bug to gpgme.

The private key is protected by a password, you can provide your own password or generate a random one with ruby:

1
2
3
4
> require 'openssl'
 => true 
> OpenSSL::Digest::SHA1.hexdigest("#{Time.now}")
 => "fc97f3c09daa072b4699d3ebb0b287ed22589f37"

To generate the keys with openssl we will use the unix command line:

1
2
3
4
5
6
7
8
9
10
11
$ openssl genrsa -des3 -out private-key.pem 2048
Generating RSA private key, 2048 bit long modulus
............+++
............+++
Enter pass phrase for private-key.pem:
Verifying - Enter pass phrase for private-key.pem:
Now we will extract the public key from the private key:

$ openssl rsa -in private-key.pem -out public-key.pem -outform PEM -pubout
Enter pass phrase for private-key.pem:
writing RSA key

Now that we have the keys, we can encrypt data with the following ruby code:

1
2
3
4
5
6
7
require 'openssl'

public_key = File.read('public-key.pem')
plain_data = 'My secret is the color blue'

key = OpenSSL::PKey::RSA.new(public_key)
encrypted_data = key.public_encrypt(plain_data)

The encrypted_data is binary data, so if you want to send in the body of an email or as part of a json request, you will need to convert it to a Base64 string:

1
2
require 'base64'
string = Base64.encode64(encrypted_data)

Ok, now, the encrypted data is only useful if we can decrypt it, that will be done with, assuming the data encrypted is Base64 encoded:

1
2
3
4
5
6
7
8
9
10
11
12
require 'openssl'
require 'base64'

private_key = File.read('private-key.pem')
password = 'fc97f3c09daa072b4699d3ebb0b287ed22589f37'
encrypted_data =
"kGll3oEEtHGavEaMVdlHJMZ4qvjEntV1D9uMoOHk+uLkmdK84enDte3Rvxtw9vdA
2mUwjc/V2Mvib7lFeZBvhYLtg0pCGu15qdOVH5I7PmyjM6xnF9YQC0ceBawxkPxX
UJWhGUp9HxTW1rmUun/mgBK6iOjOcoCF1Ggmkx7SnJOxqrU6P69pHA=="

key = OpenSSL::PKey::RSA.new(private_key, password)
plain_data = key.private_decrypt(Base64.decode64(encrypted_data))

As we mentioned above, this will only allow us to encrypt small amounts of data, to encrypt more data we will need symmetric-key encryption. You can then use the public-key encryption to protect your symmetric-key.

We will see symmetric-key encryption with ruby in another post.

Ordinalize Numbers in Current Locale

| Comments

Hi, today’s tip is about how to ordinalize numbers in current locale, ActiveSupport by default ordinalize the numbers in english, if we want to translate these values to the current locale language we may need to extend ActiveSupport.

After googling a little I found this post that solves the issue, here is my implementation based on that approach.

The ordinalize method is implemented on the ActiveSupport::Inflector module, so we will override that method, Rails provides a place where you can put these overrides, in config/initializers/inflections.rb. Since it is a script executed during the initialization of Rails, you will need to restart the server to use this method.

Here is the config/initializer/inflections.rb file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
module ActiveSupport
  module Inflector
    def ordinalize(number)
      abs_number = number.to_i.abs
      rules = I18n.t 'number.ordinals', :default => ""

      # Assume English for compat
      rules = {
        :'\A\d{0,}(11|12|13)\z' => "%dth",
        :'\A\d{0,}1\z'  => "%dst",
        :'\A\d{0,}2\z'  => "%dnd",
        :'\A\d{0,}3\z'  => "%drd",
        : other => "%dth"
      } if rules.empty?

      match = rules.find do |rule|
        Regexp.new(rule[0].to_s).match(abs_number.to_s)
      end

      match = match && match[1] || rules[:other]

      match % number
    end
  end
end

After adding the override, if we try to ordinalize numbers in other locales we will still get the default english ordinal value. To make our code work, we need to specify how to ordinalize the numbers in other locales, this is done in the config/locales/*.yml files.

For example, to ordinalize numbers in Spanish(Argentina), we modify the file config/locales/es-AR.yml.

1
2
3
4
5
6
7
8
9
10
es-AR:
  number:
    ordinals:
      \A{0,}(1|3)\z:   "%dro"
      \A{0,}2\z:       "%ddo"
      \A{0,}(4|5|6)\z: "%dto"
      \A{0,}(7|0)\z:   "%dmo"
      \A{0,}8\z:       "%dvo"
      \A{0,}9\z:       "%dno"
      other: "%d"

There you go, to test this in rails console, you can do:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
1.9.2p320 :001 > I18n.locale = 'es-AR'
 => "es-AR" 
1.9.2p320 :002 > (1..20).each {|x| puts x.ordinalize }
1ro
2do
3ro
4to
5to
6to
7mo
8vo
9no
10mo
11ro
12do
13ro
14to
15to
16to
17mo
18vo
19no
20mo
 => 1..20

Hope you can find this piece of code useful.