“...I've been working since 2008 with Ruby / Ruby on Rails, love a bit of Elixir / Phoenix and learning Rust. I also poke through other people's code and make PRs for OpenSource Ruby projects that sometimes make it. Currently working for InPay...”

Rob Lacey
Senior Software Engineer, UK

ActiveRecord scopes and lambdas

Had another annoying issue with posts on this blog not appearing immediately after being published.

class Post < ActiveRecord::Base
  scope :published, where(['published_at IS NOT NULL AND published_at < ?', Time.now])
end
</pre></code>

So any Post  with a published_at in the past should be found in Post.published.all for example. The post is missing. I thought this was an issue in *production* so I enabled logging and redeployed.

<pre><code>
Robl::Application.configure do
.....
  # Set to :debug to see everything in the log.
  # config.log_level = :info
  config.log_level = :debug
.....

Looking at the log it seems fine initially, but then I realise that the timestamp for the published_at date is the same ‘2014-09-29 09:40:59’ seconds after the the page is reloaded.

D, [2014-10-02T21:51:22.979289 #4499] DEBUG -- :    (0.3ms)  SELECT COUNT(*) FROM `posts` WHERE (published_at IS NOT NULL AND published_at < '2014-09-29 09:40:59')
D, [2014-10-02T21:52:56.305813 #4499] DEBUG -- :   Post Load (0.2ms)  SELECT `posts`.* FROM `posts` WHERE (published_at IS NOT NULL AND published_at < '2014-09-29 09:40:59') ORDER BY published_at DESC LIMIT 25 OFFSET 0
...
D, [2014-10-02T21:52:56.384903 #4499] DEBUG -- :    (0.2ms)  SELECT COUNT(*) FROM `posts` WHERE (published_at IS NOT NULL AND published_at < '2014-09-29 09:40:59')
...

Since Time.now is apparently standing still a bug in the model scope definition is incorrect. The where doesn’t evaluate Time.now every time the scope is called it evaluates it when the class is loaded. The ActiveRecord Query needs to be placed inside a lambda in order that its contents are evaluated when the scope is called.


class Post < ActiveRecord::Base
  scope :published, -> { where(['published_at IS NOT NULL AND published_at < ?', Time.now]) }
end

And success. Time to redeploy.

Customise attribute names of ActiveRecord objects

Ran into a problem where by the name of the field in our database doesn’t properly reflect the human name of the attribute.

e.g. User#some_id

[12] pry(main)> User.human_attribute_name :some_id
=> "Some"
[13] pry(main)> user = User.new
=> #<User id: nil, some_id: nil>
[14] pry(main)> user.errors.full_messages
=> ["Some should be valid"]

So ‘Some’ is a bit meaningless. But we can change this in the i18n config files like so.

en:
  activerecord:
    attributes:
      user:
        some_id: Something much more awesome
</pre></code>

And then you get this....

<pre><code>
[17] pry(main)> User.human_attribute_name :some_id
=> "Something much more awesome"
[18] pry(main)> user = User.new
=> #<User id: nil, some_id: nil>
[10] pry(main)> user.errors.full_messages
=> ["Something much more awesome should be valid"]

Sweet!

Are you vulnerable to Shellshock

The recently reported Bash vulnerability Shellshock should be tackled as soon as possible on all Unix based systems. For me it was my personal server, client servers, desktops, laptops and all servers in our production cluster. That’s a lot of servers.

env x='() { :;}; echo vulnerable' bash -c 'echo this is a test'

If you’re vulnerable you’ll see

vulnerable
this is a test

If you’re all good you’ll see

bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `x'
this is a test

If you’re vulnerable take steps to upgrade bash as soon as possible.

Change your Rails time and date formats in i18n translation locales

Needed to tweak the time format from the default “Sat, 27 Sep 2014 17:32:10 +0000” to “September 27, 2014 at 17:32”. You can do this in config/locales/en.yml like so

en:
  site_name: "RobL"

  date:
    formats:
      default: "%Y-%m-%d"
      short: "%b %d"
      long: "%B %d, %Y"
  time:
    formats:
      default: "%B %d, %Y at %H:%m"

Don't subclass Struct.new

Ran into a really irritating issue this week. While trying to test a new install of Resque . Attempting to run a worker kept return a ‘subclass mismatch error’ on some classes in our Rails application. Our Blah::User class was seemingly being reloaded and on the second reload the anonymous parent class had a mismatch. Make sense.

module Blah
  class User < Struct.new(:id, :email)
    def to_s
      "#{id} #{email}"
    end
  end
end

According to this Reddit post you shouldn’t subclass structs. Taking another look at this the above seems incorrect, I never noticed it before but the above would create a new anonymous Struct class and would immediately subclass it. The anonymous class on it’s own is not required, and it appears is the cause of this class loading oddness. The problem is resolved when we define the Struct without subclassing and we haven’t got any anonymous Struct classes using up memory.

module Blah
  User = Struct.new(:id, :email) do
    def to_s
      "#{id} #{email}"
    end
  end
end

xterm-256color: unknown terminal type

Trying to run `top` on an Ubuntu server from OSX Mountain Lion results in the following.

root@server:~# top
'xterm-256color': unknown terminal type.

Thanks to Corentin Leclerc for the solution http://blog.corentinleclerc.com/terminal-sur-macos-x-lion-xterm-256color-unkn

Add the following to ~/.profile or ~/.bash_profile

export TERM="xterm"

Restart your terminal, or open a new tab. Magic.

root@server:~# top

top - 10:52:46 up 31 days, 16:34,  1 user,  load average: 0.04, 0.02, 0.00
Tasks:  57 total,   1 running,  56 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:    786652k total,   772360k used,    14292k free,   181920k buffers
Swap:        0k total,        0k used,        0k free,    46000k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                                                                                                                              
26479 rails     20   0 89604  57m 2428 S  0.3  7.5   0:04.08 ruby1.8                                                                                                                                                                                               
    1 root      20   0  1952  508   72 S  0.0  0.1   0:13.04 init                                                                                                                                                                                                  
    2 root      15  -5     0    0    0 S  0.0  0.0   0:00.12 kthreadd

Recover committed (deleted) file in Git

What if, just suppose, you deleted a file in error, made the commit to Git, then several commits later you realise you needed the file all along. How do you get it back?

Well, you find the last commit for that file and then checkout the file with the revision number. In just a few lines then…

Robs-iMac:repo rl$ file='app/views/previously_deleted.html.haml'
Robs-iMac:repo rl$ echo $file
app/views/previously_deleted.html.haml
Robs-iMac:repo rl$ git checkout $(git rev-list -n 1 HEAD -- "$file")^ -- "$file"

Raspberry Pi - part 1

This year my main festive gift from the mighty Kat was a long awaited Raspberry Pi. Just never seemed to have the funds to nab one myself and I am pretty chuffed. If you’ve not heard of one then you’ve been living under a rock for the last year. The Raspberry Pi is basically just a very small, barebones computer. In fact its so minimal that it doesn’t even come with a case.

Raspberry Pi

You can see on the board that the mounted interfaces are a dual USB port, micro-USB power supply, HDMI output to monitor, audio out, video out, GPIO pins.

You might have enough bits and bobs lurking in your cupboard full of cables and old hardware to get going but alas I do not. So in order to get started I need some way of hooking this up to a monitor, keyboard and powering the thing.

USB Keyboard

No PS2 ports so its all USB, so a USB Keyboard is needed. Relatively cheap, I’ve spotted a great wireless one with a touch pad for £25 but for now this one will do.

Monitor

While the Raspberry Pi can be easily used with a modern television I can’t see myself sitting in the front room while I’m playing with it for the time being. You can use any monitor or television with an HDMI or DVI connection. So you’ll need a cable

My spare monitor is a VGA which won’t work without an adapter to convert the signal. £30 for an adapter is a bit much really. I’ve secured a DVI monitor from a friend for £10, so I’ve opted for the HDMI to DVI while I’m playing.

SD Card / Operating System

You’ll need an SD Card to install the operating system on. Fortunately we have an old 4Gb card from a Camera. So cost £0. Yay. average cost on Amazon about £6 so not bad.

Install it yourself

You can follow the tutorial on the Raspberry Pi Downloads page to copy an OS onto a card.

Pre-installed

You can get an 8Gb (and upwards) SD Card from ThePiHut with one of two distributions from £8.99.

  • Raspbian – pre-installed Raspian is an optimised version of Debian, containing LXDE, Midori, development tools and example source code for multimedia functions.
  • OpenElec / XBMC – pre-installed Open Embedded Linux Entertainment Center, or OpenELEC for short, is a small Linux distribution built from scratch as a platform to turn your computer into a complete XBMC media center.

That’s a start I’ve ordered what I need so now I have to sit and wait. I’ve got a few ideas about what I’d like to build.

  • MAME centre
  • Media centre
  • Spotify streaming straight into the HiFi

So I’ll do a bit of research and buy a book or two.

Resources

There’s plenty of resources out there as well as some physical publications to get started with.

More useful links…

Installing 'therubyracer' grrrr

Robs-iMac:testapp rl$ gem install therubyracer
Building native extensions. This could take a while…
ERROR: Error installing therubyracer:
ERROR: Failed to build gem native extension.

/Users/rl/.rvm/rubies/ruby-1.8.7-p370/bin/ruby extconf.rb
  • extconf.rb failed *
    Could not create Makefile due to some reason, probably lack of
    necessary libraries and/or headers. Check the mkmf.log file for more
    details. You may need configuration options.

Provided configuration options:
—with-opt-dir
—without-opt-dir
—with-opt-include
—without-opt-include=${opt-dir}/include
—with-opt-lib
—without-opt-lib=${opt-dir}/lib
—with-make-prog
—without-make-prog
—srcdir=.
—curdir
—ruby=/Users/rl/.rvm/rubies/ruby-1.8.7-p370/bin/ruby
extconf.rb:13: uninitialized constant Gem (NameError)
Checking for Python…

Gem files will remain installed in /Users/rl/.rvm/gems/ruby-1.8.7-p370@thebevy/gems/libv8-3.3.10.4 for inspection.
Results logged to /Users/rl/.rvm/gems/ruby-1.8.7-p370@thebevy/gems/libv8-3.3.10.4/ext/libv8/gem_make.out

It seems that libv8 requires Gem to exist, however rubygems is not available by default in Ruby 1.8.7. Ruby 1.9.x it is.

Thanks to Olly Smith for the solution

Robs-iMac:thebevy rl$ RUBYOPT=-rrubygems gem install therubyracer
Building native extensions.  This could take a while...
Fetching: therubyracer-0.10.2.gem (100%)
Building native extensions.  This could take a while...
Successfully installed libv8-3.3.10.4
Successfully installed therubyracer-0.10.2
2 gems installed
Installing ri documentation for libv8-3.3.10.4...
Installing ri documentation for therubyracer-0.10.2...
Installing RDoc documentation for libv8-3.3.10.4...
Installing RDoc documentation for therubyracer-0.10.2...

Apache Rewrite because I can never remember how to do it

I seem to use Apache less and less these days, so every year or so I have to try and remember the syntax for VirtualHost configs, redirects and the like.

<VirtualHost *:80>
  ServerName duncanwilkinson.com
  DocumentRoot /home/duncan/www.duncanwilkinson.com/
  RackEnv production
  RewriteEngine on
  RewriteCond %{HTTP_HOST} !^duncanwilkinson\.com
  RewriteRule ^/(.*)$ http://duncanwilkinson.com/$1 [R=permanent,L]
  CustomLog /var/log/apache2/loathsome-access.log combined
  ErrorLog  /var/log/apache2/loathsome-error.log
</VirtualHost>
<VirtualHost *:80>
  ServerName www.duncanwilkinson.com
  ServerAlias www.dna-labs.net dna-labs.net www.triplebinary.com triplebinary.com www.needleye.net needleye.net
  RewriteEngine on
  RedirectMatch (.*) http://duncanwilkinson.com
</VirtualHost>
<VirtualHost *:80>
  ServerName www.collapse.co
  ServerAlias collapse.co
  DocumentRoot /home/duncan/www.collapse.co/
</VirtualHost>
GPK of the Day Bad Breath SETH