Technology and Software, Tips

Upgrade a Rails 4 app to Rspec 3

I have a Rails 4 application with Rspec 2. I’m using a mix of should and expect assertions. I wanted to upgrade to Rspec 3 without changing the specs for now. I updated the Gemfile, run bundle install, rake spec and got many errors. Basically most helpers went missing (undefined methods visit, sign_in, root_path, etc., plus anything defined inside app/helpers). Googling around I found a solution for everything but the keys to restore the old behaviour are two.

1) The new rspec doesn’t include helpers based on the directory the specs are stored into. You either define the spec type with stuff like type: :feature or type: :controller or you add

config.infer_spec_type_from_file_location!

to the Rspec.config block.

2) The should syntax has been deprecated and doesn’t work any more by default. You must enable it with

config.expect_with :rspec do |c|
c.syntax = [:should, :expect]
end

Minor quirks:

  • You must remove require ‘rspec/autorun’
  • example doesn’t exist anymore. It has been replaced by RSpec.current_example
Advertisement
Standard
Technology and Software

FactoryGirl and Paperclip: testing content types

I used Paparclip to add a picture to a model, something I did for years. This time I also added a validation for content types, and this might be a first time for me (I don’t want to grep all the models of all the past projects). The validation is

validates_attachment :picture,
content_type: { content_type: ["image/jpg","image/png"] }

Now I want to test it. I was loading real image files in the objects created with FactoryGirl. This is the code

picture  { File.open("#{Rails.root}/#{%x[ls test-images/*jpg].split("\n").sample}") }

Note that I’m using %x[].sample to randomly pick an image from a directory, but that’s not important.

The code above doesn’t set a mime type and the validation fails. I had to google quite a lot to find the right hints (some solutions have been obsoleted by newer versions of Paperclip and maybe other parts of the toolchain). The solution is

Rack::Test::UploadedFile.new("#{Rails.root}/#{%x[ls test-images/*jpg].split("\n").sample}"), "image/jpg")

which loads the image and sets it’s content type.

Standard
Technology and Software

Espruino, first impact

I received my Espruino yesterday and this is the tale of my first impact with it as a pure software developer with no harware skills to talk about.
Conclusions first: it’s going to be fun and I’ll learn many things. But how long it will take? Read on.
Let’s define the baseline. What do I know about electronics? I know how to change a light bulb, how to connect wires to a plug, a socket, a switch. I know that resistors are for heaters or for making light in tungsten lamps. I know that capacitors are to store energy. I know that solenoids are to make transformers or antennas. That’s it.
So, I got the Espruino, unpacked it, wondered at all those wires in the package and the other little boxes (the Espruino board, a relay, two servos, a temperature sensor, lot of LEDs). There is a printed piece of paper with the url to the Quick Start page. I went there and watched the video. Then I watched this one on YouTube which is even simpler. I suggest you watch it too to understand what going on next.
I’m using Ubuntu Linux and I didn’t have the minicom program used in the example but Ubuntu tells me how to install it. First problem solved.
I connected the Espruino to my netbook with my smartphone data cable which has the same connector. Second problem solved.
I type in the commands in the video and switch the LEDs on and of and make them blink at different speeds. Great!
Then I get to 2:55. “For that you need a battery” and I obviusly have many batteries at home, AA or AAA formats, 1.5 V. Yes I also know about V and A, I’m such genius! :-) Unfortunately that means that I also know that plugging in the wrong battery could burn my Espruino. Which battery are they using? They don’t tell it but probably the specs of the Espruino will help me. Furthermore I don’t have any connector that would fit into that socket and I only have a vague idea about where to buy one. Ok, let’s take a note.
A few seconds later into the video they plug a servo into the board. There are two servos in the box I received. I get one and check it. I realize that I can’t plug it anywhere into the board. It’s got a female 3 pin plug and my board has only holes. But the board in the video is different. It’s got a lot of male pins and I realize now that at 0:20 they said “pinheads we soldered on it”. Oh… soldered. It means a need a solder. Guess what? I don’t have one and I have a vague idea of how to use it. I did it a couple of times in my life on objects much larger than these ones. Oh, I think I’ll also need some tin or lead. Let’s take another note. That’s a new skill to learn.
Luckily the box contains many pinheads. I’ll have to cut them into the sizes of the video but I can probably make it. I think they’ve been using the ones that look like the ones in the picture on this page. Ok, I don’t have the battery and I don’t have the solderer, move on to the next demo.
I have no light sensors in my box (I think) but I have a temperature sensor. I know because it looks exactly like the one in this page and in this one (and that’s my relay!)
Ok, I still don’t have a way to plug it into the board (no solderer!) but let’s pretend I can. How do I plug the temperature sensor? Oh, I need a 4.7 k resistor. I know what it is and maybe it’s one of the resistors in the box but there is nothing written on them. I guess there might be a color code and I’ll ask on the forum. Let’s take a note.
But the real question is why do I need a resistor to make the temperature sensor work? You know, I’m a software developer so my first thought is that the sensor has a bug and we must fix it. Couldn’t they sell it so that it works out of the box? OK, I’m pretty sure that the real answer will be that the sensor is perfectly fine and I need the resistor for some reason that I can’t understand given my almost zero knowledge of electronics. I even found page with a picture of the sensor plus the resistor – it looks like the ones in my box. Let’s move on.
Looking at the relay I see some good news: I know how to connect wires to it, it’s like what’s inside a plug :-)
So, let’s recap: no battery, no idea about the voltage, no connector for the battery, no solderer, no idea about why I need resistors but a guess about which one to use. All of that has hinted me again about why hardware is hard and confirmed my old choice to turn to software. But learning things is great so I’ll google around and find solutions. And I’ll stop by an electronics store and buy some tools.

Standard
Technology and Software

Build Mobile Chrome Apps from the command line

Mobile Chrome Apps are great news. I’m finally able to create an Android app using the technologies I know best: HTML, CSS and JavaScript. Not a single line of Java. If you don’t have to use Java you don’t need to use an IDE but how to build it without Eclipse or the like?
Here is how to do it using only command line tools. This is useful in many automation scenarios.

cd
git clone git://github.com/MobileChromeApps/mobile-chrome-apps.git
mobile-chrome-apps/mca create eu.connettiva.MyApp
cd MyApp/www
vi config.xml    # write your data
vi manifest.json # write your data
vi background.js # edit it if you're app doesn't
                 # start with index.html

Write your code, then build the Android app.

cd ..
../mobile-chrome-apps/mca build --release
      # or --debug if you don't want to sign the app

The first time you sign you need to generate the keys

keytool -genkey -v -alias MyApp -keyalg RSA \
  -keysize 2048 -validity 10000 -keystore MyApp.keystore

You must sign the apk and align it every time you build it.

jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 \
  -keystore MyApp.keystore \
  platforms/android/bin/MyApp-release-unsigned.apk \
  MyApp
zipalign -f -v 4 \
  platforms/android/bin/MyApp-release-unsigned.apk MyApp.apk

Finally run the app in an emulator. Get the list of available devices with

android avd

and start one of them. Then install the apk in the emulated device with

adb install MyApp.apk # install -r (reinstall)

It’s ready to be used now!

If at any time mca tells you to run mca init to update itself do this:

cd ~/mobile-chrome-apps
./mca init
Standard
Technology and Software

Logging Skype events

On a whim I started looking at the advanced notification panel in Skype (Options, Notifications, Advanced View) and found out that we can run a script on events. Wow, that means we can get the details of a Skype event over the command line into any interpreted or compiled program.

My first attempt has been a very simple bash script (I’m on Linux)

echo $* >> skype.log

The name of the script must be typed in into the box in the options panel with some parameter variables. There is little documentation about them but after a little googling and a look at the output of strings /usr/bin/skype | egrep ‘^%’ I got this list: %type, %sskype, %sname, %fpath, %fname, %fsize, %fprogress, %fspeed, %smessage.

I’m calling my script as log-skype %type %sskype %sname %smessage and it’s still very simple:

#!/bin/bash
echo “`date +’%Y-%m-%d %H:%M:%S’`” $* | sed ‘s/ %smessage$//’ >> ~/skype.log

The sed is to remove %smessage from the lines about the events that don’t have a text message.

This lets me build a plain text log of all my messages. Unfortunately it seems there isn’t a variable with the name of the conversation but that’s not a problem.

The next step could be integrating the events with the dbus but there are already other web pages about that.

If you want to inspect Skype’s message databases you might also be interested in Skyperious.

Standard
Technology and Software

Ruby on Rails Archeology and Restoration

I’m experiencing a time travel back to 2006. That was when I wrote my very first Ruby on Rails application and this week I had to take it out of the archives and make it run again. I run into a few entertaining hurdles and had to perform some tricks that might be useful to know.

I think it started as a Rails 1.x application and it was upgraded until 2.3.2. I had to upgrade it to 2.3.18 now because of the vulnerabilities discovered among the years.

The application is so old that it didn’t have a Gemfile. Creating one is simple (only 7 gems, the ecosystem was tiny at the time) but the versions of the gems must be picked with care. It runs with nothing newer that rake 0.8.7, rubygems 1.6.2 and Ruby 1.8.7. Follow this tutorial to adapt the application to bundler or you’ll run into troubles in production mode (methods not found, etc).

To install ruby-18.7-p371 I had to specify the rubygem version with rvm install ruby-1.8.7-p371 –rubygems 1.6.2 or run into “There was an error while trying to resolve rubygems version for ‘latest'”.

Thanks to the pg gem it keeps working with PostgreSQL 9.2 (it started with 8.1) but I was using some stored procedures more for fun that for real need (but they were definitely faster than AR). I was accessing the recordset data with connection.exec(query).result. That doesn’t work anymore. Sometimes in the last years the result method has been replaced by values.

I was using gettext  to handle internationalization because Rails didn’t have an internal i18n framework at the time. By the way, I think that gettext is still a better and higher level framework than what we have now, especially because it can parse Ruby sources, collect the new translations and add them to the translation files marking them as untranslated. Anyway, all the world uses I18n, it’s pointless to mix the two of them and gettext was abandoned. But the latest version of the gem is not compatible with Rails 2.3.5+. Big problem with 600+ translations to handle. Luckily there is a commit that fixes that.

gem “locale_rails”, :git => “git://github.com/mutoh/locale_rails.git”, :ref => “13a096f20b”

The application ran on a mongrel_cluster behind an apache reverse proxy. bundle install looks for mongrel 1.1.6 which can’t be found anywhere on the Internet but version 1.1.5 works and is on github. However with mongrel_cluster I’m having some wierd problems in the inner working of my application. Running mongrel without the cluster works fine, so I ended up starting the individual mongrel processes manually. That’s good enough until I investigate the issue and try to move the application to passenger. Should I port it to Rails 3.2? We’ll see what happens but did I mention that the JavaScript front end (some 3000 lines) is based on dojo.js and it’s pub/sub infrastructure? It’s a steep cliff to climb.

The application deals with timezones using the tzinfo gem but apparently the timezone names generated by Rails  are no more what tzinfo expects. As an example, Rails’s select helper generates “London” as a value but tzinfo wants “Europe/London”. I had to implement my own helper along the lines of TZInfo::Timezone.all.map{|tz|”<options value=\”#{tz.identifier}\”>#{tz.to_s}</options>”} Actually it’s much more complicated because I also wanted to display the offset from UTC and sort by it. Maybe I’ll add a gist. I didn’t investigate the helper issue but this should apply to Rails 3.2 as well because I used the latest version of tzinfo. By the way, TZInfo doesn’t the some possibly embarrassing glitches of ActiveSupport::TimeZone, which among the others places Edinburgh into the Europe/Dublin timezone (a different country) or Bern into Europe/Berlin (again, why not Europe/Bern?). It has no Edinburgh and Bern at all but sometimes less is better. Working with timezones is always a messy business.

Eventually it runs.

A few random notes:

It still uses .rhtml files. I forgot they existed. Did you?

It was originally versioned with CVS, not even subversion, but mercifully I moved it to git years ago and forgot I did. It was a nice surprise.

This is Rails 2.3 so you manage the application with ruby script/server and ruby script/console, rails s didn’t do what I’m used to now.

Last but not least it starts up much quickly than the Rails 3.2 applications I’m working on, probably thanks to the small number of gems it uses.

Standard
Technology and Software

emacs:// URLs in Ubuntu

I’ve been experimenting with the better_errors gem and I discovered that vim handles mvim:// urls. That’s nice because the gem turns the file name in the error message into a URL that opens the file in the editor at the line of the error. I’m an emacs user and want to have the same feature. I use Ubuntu with Gnome so my solution works in that desktop environment.

I got three browsers on Ubuntu: Firefox, Chrome, Opera. They must handle URLs like @emacs://+20 ~/.bashrc@.

If we prompt Firefox with that URL it will ask us to associate a program to it so we only need to create a bash script that extracts the line number and the file name from the URL and passes them as arguments to emacsclient.

Chrome uses xdg-open, which needs a .desktop file that describes which program to run.

Opera must be configured: Edit preferences, Advanced, Programs, Add… and then Protocol: emacs, Open with other application: the path to the program.

This is the program that calls emacsclient:

#!/bin/bash

args=`echo $* | sed -e "s/^emacs:\/\/+\([0-9]\+\)\(.*\)$/+\1 \2/" -e 's/%20/ /g'`
line=`echo $args | cut -f1 -d" "`
file=`echo $args | cut -f2- -d" "`
/usr/bin/emacsclient.emacs-snapshot -n $line "$file"

Put it somewhere in PATH, maybe ~/bin/emacsclient-url, and make it executable.

Open @emacs://+20 ~/.bashrc@ in Firefox and associate it to the program. Check that it opens the file in emacs (emacs must be already open). Check that URL in Opera too. Chrome’s turn now.

The .desktop file for xdg-open must be located in the /usr/share/applications/ directory. Let’s call it emacs-client-snapshot.desktop

[Desktop Entry]
Version=1.0
Encoding=UTF-8
Name=Emacs Client Snapshot (GTK)
GenericName=Emacs
Comment=GNU Emacs Client Snapshot Text Editor
Exec=/path/to/emacsclient-url %u
Terminal=false
Type=Application
Icon=emacs-snapshot
Categories=Development;Utility;TextEditor;
MimeType=x-scheme-handler/emacs
NoDisplay=true

Run sudo update-desktop-database and test with xdg-open “emacs://+6 ~/.bashrc”. Check that the URL opens in Chrome too.

Finally, to use those URLs in better_errors we must add this line to our code, possibly a Rails initializer.

BetterErrors.editor = Proc.new{|file, line| "emacs://+#{line} #{file}"}

Be sure to try that gem.

Standard
Technology and Software, Tips

Starting the VirtualBox interface at 192.168.56.1

I like to have some virtual machines arranged as I described in my post VirtualBox 4: NAT + Bridged Networking. To let them access the development servers I run on the host system I bind them to the VirtualBox network adapter vboxnet0 at 192.168.56.1. The problem is, this interface doesn’t exist until a VirtualBox’s VM starts and if I run one of those servers with Apache (as a proxy or a mod_php application) Apache won’t start. There is a little trick to start the interface even without running VirtualBox. This is for Linux:

VBoxManage list vms
sudo ifconfig vboxnet0 192.168.56.1

That VBoxManage command comes from here. You can hide it’s output with > /dev/null 2>&1

What it does is listing the virtual machines configured in VirtualBox but as a side effect it creates the network interface. No more tedious operations of running VirtualBox, starting a VM and closing it just to get the interface up!

Standard
Technology and Software

Globalize3, unknown attribute: translations_attributes

Another easy one with the twist that I couldn’t google the error message, which basically never happens. Either it’s a nasty bug or I did some really dumb mistake. Chances are that… wait, which one are you betting on?

So, the error occurred inside the update_attributes of a controller’s update method. The problem is that it saves the data coming from a very big form with many nested models with many accepts_nested_attributes_for. Some of those models are translated with globalize3 and there are no hints about which one triggered the error. It looked hard to debug but hopefully I did something dumb, right?

My first thought was that I forgot to create the translation tables in some globalized model but no, there they are. My second thought was that I forgot to add either a call to translates or something like that. It turned out that I forgot  accepts_nested_attributes_for :translations in a couple of models.

Dumb indeed but there is a post to google for this error now!

Standard
Technology and Software

Keep the browser open with Capybara and Selenium

The combination of Capybara and Selenium is great for testing complex web applications but it’s really annoying that the browser window closes when there is an error. All is left for debugging is the Ruby error message on the console but all the information about the HTML page and JavaScript code is lost, and the cause of the error might be there.

There are a few threads about this problem (just google the title of this post) and this is the code that worked for me, built on the suggestions found in a couple of them.

Capybara::Selenium::Driver.class_eval do
  def quit
    puts "Press RETURN to quit the browser"
    $stdin.gets
    @browser.quit
  rescue Errno::ECONNREFUSED
    # Browser must have already gone
  end
end

It’s a monkey patch of what I found in gems/capybara-1.1.2/lib/capybara/selenium/driver.rb and I put it in a file loaded by spec_helper.rb

I just added the puts and the gets lines to the original code.

There is a last annoyance left: the browser doesn’t stop at the page that triggered the error but it stops on a blank page. I have to click the back button to get to the page with the error, which might not always work. If anybody knows how to stop on the page with the error please leave a comment. Thanks!

Standard