Category Archives: Ruby on Rails

Leveraging C++ open source in rails apps

One thing that many software developers neglect is the build/buy decision.   Often it is more cost effective to buy an existing solution rather than build your own.   This can happen at the macro level as well – inside your custom-built solution, problems may be solved using libraries written by others.   If that library happens to be open source, all the better!

But what if the best solution out there is written in some other language?   I ran into this very scenario when I came across an ideal open source solution written in C++ that I wanted to use in my Rails application.   The solution implements a very complex data structure and support code, and would add zero value to my application by trying to do it from scratch.  There is nothing like that library in the Rails ecosystem. 

To the Rescue: Foreign Function Interface, FFI.  This is, in itself, a very impressive piece of work.  With just a few lines of code to bind the interfaces, you can literally call natively compiled code from Ruby.  

You add a gem to your Gemfile:

gem 'ffi'

Then develop a bridge between the rails and c++ spaces.

  1. Declare all external interfaces in a .h file for C++ to name/externalize them properly
  2. Use FFI’s DSL to declare the bridge specifics

The header file (simplified for presentation):

extern "C" {
  void addBlock(Index *idx, int64_t start_day, int64_t start_hour, int64_t end_day, int64_t end_hour, int64_t id);
  int64_t get_right(return_right_down* rrd);
  int64_t get_down(return_right_down* rrd);
  int64_t get_corner(return_right_down* rrd);
}

The DSL:

module SpecialLibrary
  extend FFI::Library

  ffi_lib 'c'
  ffi_lib_flags :now, :global
  ffi_lib './lib/special/libspecial_schedtool.o'

  attach_function :addBlock, [:pointer, :int, :int, :int, :int, :int], :void
  attach_function :get_right, [:pointer], :int
  attach_function :get_down, [:pointer], :int
  attach_function :get_corner, [:pointer], :int
end

The functions declared in the header file are implemented by you in a C++ file and compiled to a .o declared using the ffl_lib syntax in the DSL above; those functions call C++ library API entries in your leveraged library (libspecial in my case), which is built according to the supplier and installed on the system as a library.

If that’s not impressive enough, it works on Ubuntu and OSX.  The commands to do the C++ compilation of the interfaces is different, but the code itself needs no changes.   I put this little script together to build on either system:

#! /bin/bash
#
# Different commands on OSX v Linux
case `uname` in
'Darwin')
    g++ -std=c++0x -I/usr/local/include/ -L/usr/local/lib libspecial_schedtool.cpp -lspecialindex_c -lspecialindex -dynamiclib -o libspecial_schedtool.o
    ;;
'Linux')
    g++ -std=c++0x -fPIC -I/usr/local/include/ -L/usr/local/lib libspecial_schedtool.cpp -lspecialindex_c -lspecialindex -shared -o libspecial_schedtool.o
    ;;
*)
    Echo "Error: don't know how to compile on this platform"
esac


Honestly, my app would not exist today without this leverage.  

Bundler SSL failures using rails-assets.org

I recently discovered a cool way to use Bower assets in rails applications from these guys.   I want to give a great shout out to  who provide an example application you can clone that is a good learning example on how use Restangular with Rails.

That was the good news.  I have an OSX development machine running 10.10 that I did that work on and it worked great.   My laptop running 10.11 however, would fail to bundle the assets from rails-assets.org.   It was complaining about SSL certificates and I had no idea how to deal with that.  My configuration is rvm 1.27.0, Jruby 9.0.5.0, rails 3.2.22.2, JDK 1.8.

I found an easy test to run quickly to compare environments and test for the problem:

ruby -e 'require "net/http"; require "uri"; require "jruby-openssl"; puts "ruby: "+RUBY_VERSION; puts "openssl: "+OpenSSL::OPENSSL_VERSION;Net::HTTP.get(URI("https://rails-assets.org"))'

If that fails, but changing rails-assets to rubygems succeeds, then you probably have the same problem and can try my solution.  What I don’t quite understand is how that test fails on OSX 10.10, yet the bundle install succeeds.

When using Jruby, the certificates are stored in the JDK.   You can use part of a recommended solution to find out where they are:

rvm osx-ssl-certs status all

It will return something like:

Certificates for /Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home/jre/lib/security/cacerts: Up to date.

That cacerts file is a keystore.  You need to add the root certificate used by rails-assets.org to that keystore. There are probably different ways to do it, but Firefox allows you to export the certificate easily:

  1. Browse to rails-assets.org
  2. Click the lock icon, then the right arrow, more information,  view certificate, details
  3. Click the root certificate (DST Root CA X3)
  4. Click export, save to a file ending in .pem, with format X509 certificate.  In my example I saved to ~/Desktop/DSTRootCAX3.pem

Now put it in your keystore:

cd /Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home/jre/lib/security/
sudo keytool -import -trustcacerts -alias root -file ~/Desktop/DSTRootCAX3.pem -keystore cacerts

(Note that the default password for the keystore is ‘changeit’)

That import fixes the ruby one line test above for 10.10 and 10.11, for JDK 1.7 and 1.8.

Things that seemed good but did nothing:
Several solutions here.

  1. Try bypassing ssl by using http in your gemfile (it must redirect to SSL because this does not work).
  2. gem update –system. No apparent effect
  3. put ‘:ssl_verify_mode: 0‘ in your ~/.gemrc.   This has the effect of getting past the first level of certificate error, but fails installing specific bower assets.   Further, it isn’t a good solution because it’s disabling ssl.
  4. use rvm to install ssl before installing ruby:  Doesn’t work for Jruby — the build is done with maven and the option for the ssl directory is not supported.

This looked promising.  Unfortunately on my laptop, the “rvm osx-ssl-certs update” ends up corrupting the JDK keystore! Instead of a keystore, it puts a text file containing certificates in its place, and subsequent failures start complaining about an invalid keystore. You’ll need to reinstall the JDK or recover the certificate file from a backup. The other solutions in the page simply don’t work.

Rails pluralization / uncountable nouns

I was building a Rails application today with a noun that has interesting pluralization rules: fish. Fish is both singular and plural, which causes a little complexity for the “convention over configuration” strategy of Ruby. In the past I’ve worked around this by using nouns that don’t have this characteristic, but wanted to figure this out this time.

The issue is that for a noun like “bird”, the convention is that we list all the birds in the database by going to a url like http://app/birds, and a specific bird by selecting its ID in the URL like so: http://app/bird/27. That’s the convention in the routing logic. The challenge then, for “uncountable nouns” like fish, is that the routing logic thinks that http://app/fish is an error, because it’s singular and needs a trailing /ID.

I stumbled over this posting, which is excellent and helped me understand more about what Rails is doing under the hood. So after I removed all my hacky workarounds that didn’t work (include forcing a “Fishes” controller) I noticed that “rake routes” has some lines of interest (reduced for brevity):

            birds GET    /birds(.:format)                  birds#index
             bird GET    /birds/:id(.:format)              birds#show           
       fish_index GET    /fish(.:format)                   fish#index             
             fish GET    /fish/:id(.:format)               fish#show

Note that we have birds and bird for paths, and we have fish_index and fish! My ultimate problem was that fish_path wasn’t working in a link_to:

	<%= link_to 'Fish List', fish_path, class: "btn btn-large btn-primary" %>

that is to say, it rendered the link in the containing page, but when clicked, gave an error because of the missing ID. The solution is obvious now: replace with fish_index_path:

	<%= link_to 'Fish List', fish_index_path, class: "btn btn-large btn-primary" %>

By the way, the work is for a non profit that I’m helping out dealing with water pollution. I’ll update more later when there is something concrete to talk about.