Blog Archives

Introducing Has Face for Rails

Posted in Code, Ruby on Rails, Tips and Tricks

Have you ever created an application where users are trusted to upload their own avatars? Wouldn’t it be great if there was an easy way to ensure the avatar contains a person’s face?

Has Face is a neat little gem that uses the face.com API to ensure that an image contains a persons face. It’s very simple to use and can be easily integrated into an existing rails application.

To get started add the has_face gem to your Gemfile and run a bundle install

Can’t see this Gist? View it on Github!

Run the generator to copy over an initializer:

Can’t see this Gist? View it on Github!

The initializer should look something like this:

Can’t see this Gist? View it on Github!

Now we’ll need to make a face.com developer account. You can signup for a free account over at face.com. Once you have signed up, place your API key and API secret in the initializer config.

The last option in the initializer (skip_validation_on_error) will change the behavior of has_face when an error occurs. If set to true, when an error occurs a warning will be logged to the logfile with detailed information about the failure and face validation will be skipped. This can be useful if you want your application to function if the API service is not reachable. If the value is false then an exception will be raised when an API call fails, this will allow you to manually handle the exception yourself, please check the documentation for details on the errors raised.

Once the initializer settings are setup then we can add face validation to a model. In the example below I’m using carrierwave to attach the image to the model but other image attachment gems should also work fine (anything that correctly responds to `path` should be OK).

Can’t see this Gist? View it on Github!

That’s it, that’s all we need to have a functioning face validator. There are a few other options that I haven’t covered here in this short guide, please consult the readme for more detailed information.

Simple Database Export and Import With Character Encoding Conversion

Posted in Code, Ruby on Rails

There is a gem called ydd that offers really simple import and export of smallish databases. It exports to YAML and then imports to whatever database Rails can connect to. After using YDD a few times I’ve found it easier to pinpoint the cause of problems that occur using taps.

It doesn’t handle character encodings though so I went about adding that. With the handy rchardet gem and IConv, detecting the character encoding of the incoming string and converting it to UTF-8 was pretty simple. I’ve created a pull request for the gem that will hopefully be accepted.

The essential code is below, and revolves mainly around the detection and conversion. Using //TRANSLIT causes IConv to try and convert the incoming character code to something that exists in the UTF8 character set, and then //IGNORE will ignore any characters that don’t exist in the UTF8 character set. Chaining //TRANSLIT and then //IGNORE will make IConv try a conversion first and then ignore anything it cannot convert.

I used this gem after the above changes to convert about 400,000 records of text data with ASCII, windows-1252, IBM866 and other character encodings from an old SQLite installation to a new postgres database without any issues.

Sending Apple Push notifications in rails with Redis and apn_sender

Posted in Code, Featured, Inside TFG, Ruby on Rails, Tips and Tricks

Sending iOS push notifications from a Rails application is very easy to do these days, thankfully there are many great Ruby gems that can be used to handle most of the magic for you. Recently I ran into the apn_sender gem which handles sending push notifications in a really neat way.

Sending push notifications directly from a Rails application can be slow and we probably don’t want to have the user waiting until the notification is sent, instead apn_sender can be setup to run a worker which is constantly connected to the apple push notification service. When there are new notifications to send, the notifications are queued up and sent through the always open connection that is maintained by the worker.

apn_sender uses redis as a message queue to keep track of the notifications waiting to be sent, you’ll need to install it before using the gem.

To add apn_sender in your Rails 3 application, just add the gem to your Gemfile. We’re going to need the daemons gem too so we’ll include that as well.

Can’t see this Gist? View it on Github!

Now we can create our daemon which we will be using for sending push notifications, this can be placed anywhere, I’ve put mine in script/apn_sender. Make sure to add execute permission to the file after creating so we can run it.

Can’t see this Gist? View it on Github!

Before the daemon can start running we’ll need to put our iOS push certificate into the application. Instructions for generating the certificates are available at the Apple Developer site. The certificates need to be placed inside of /config/certs and should be named apn_development.pem or apn_production.pem for production.

Once the certificates are in their correct locations, we can start up the daemon. The daemon does not know about the Rails environment so we need to specify this when starting it up. The daemon supports start, stop and restart commands. There is a verbose flag available to output more information (which can be helpful when debugging).

Can’t see this Gist? View it on Github!

Our application is now set up to send push notifications, this can now easily be performed by adding a new notification to the queue. The notify method on the APN class will take a push notification token and then our parameters, we can specify the alert message to show the user, whether or not we want sound as well as the number to display on the badge icon. Anything else we pass to notify will be sent as metadata in the push notification. Here’s an example of creating a notification.

Can’t see this Gist? View it on Github!

The worker should pick up the notification within a few seconds and send it off. The apn_sender has many other features that I haven’t covered, you can view the full documentation over at https://github.com/kdonovan/apn_sender.

How to Get All Associations for an Activerecord Model

Posted in Inside TFG

There was a question that was asked on our IRC channel today about how to get all the associations for an Activerecord model. I’m assuming it was to do some debugging or something, in any case I did a bit of digging around in the Rails docs and it turns out the answer isn’t that hard.

Doing something like :

    Model.reflect_on_all_associations

Will give you all the associations for that model, it’s pretty dirty though and so an easy way to tidy it up is :

    Model.reflect_on_all_associations.collect{ |association|
        association.name.to_s.classify
    }

So, as usual with Rails it was easy as pie, I just am putting this here for future use :)

Edit : Thanks to Darcy for tidying up my previous mess :P

A brief introduction to the RVM Ruby API

Posted in Code, Ruby on Rails, Tips and Tricks

As part of the work done on RVM during the Ruby Summer of Code, One of the things I worked to add was a fairly comprehensive Ruby version of the bash API.

Since then, the Ruby API has been used to build a couple of small projects and tools but it still maintains relatively undocumented.

Today, I’m going to introduce the basics of working with the Ruby API, starting by introducing the fundamental concepts you need to know and then going on to cover how the most common example of it’s use (rvm gemset support in passenger) works under the hood.

Getting started

First off, you’re going to want to make sure you actually have the Ruby API installed. If you have a remotely recent (e.g. newer than 6 or so months) copy of rvm, you’ll already have a copy – Otherwise, you’re going to need to update your rvm install using rvm update.

To load the API, open up irb and type the following:

# First, find where rvm is installed
rvm_path = File.expand_path(ENV['rvm_path'] || '~/.rvm')
# Secondly, add the ruby library to the load path
$LOAD_PATH.unshift File.join(rvm_path, 'lib')
# Finally, actually load rvm
require 'rvm'

Once said code has been executed, you should have access to RVM constant in your irb session. The method we use to require it means that it is loaded from the currently installed version of rvm so you don’t have to deal with issues related to different versions between rvm itself and the Ruby API.

The bare basics

The ruby api works on the concept of a rvm ‘environment’ – Essentially, you can think of them as the equivalent of a shell instance – They keep track of instance variables, have their own ruby / gemset selection and are sandboxed (for the most part) from other environments. Creating a new environment is as simple as doing the following in your ruby code:

env = RVM.environment 'ree'

Or, alternatively, you can pass a block and it will be called with the environment as an argument. Along side this, you have RVM.environments, which accepts multiple ruby names and calls the block with each environment.

For convenience sake, RVM exposes RVM.current, an environment that defaults to the currently loaded gemset (e.g. if you open irb in rbx@rails3, it will be an environment using rbx@rails3).

As an added bonus, when you call an undefined method on RVM, we automatically use method missing to call it on RVM.current – Hence, If RVM::Environment#some_instance_method exists, you can use RVM.some_instance_method to call it in the current environment object.

Working with environments

So, now that you know how to get environment object, you need to know how to use it. In the simplest form, the Ruby API mirrors the command line program by translating:

rvm command action arg1 arg2

Into:

env.command_action arg1, arg2

With the library automatically taking care of converting arguments (e.g. a hash as the last value will be converted to arguments to the program).

As an example, to call rvm list strings, One would use env.list_strings. Likewise, rvm use becomes env.use and so on and so forth. In these cases, use switches the environments ruby – not the running ruby itself.

One of the added features in the Ruby API is that use and gemset_use have alternatives with a bang (use! and gemset_use!) that will switch the currently loaded ruby’s gemset (by changing GEM_PATH and GEM_HOME and then telling rubygems about the change) - raising an exception if it’s for a different ruby installation. This switch makes it possibly to dynamically switch your ruby applications gemset whilst running.

Of course, dealing with a direct port of the API isn’t always nice when you’re writing a lot of code env.alias_list feels clunky compared to most ruby code and some of the tools are rough around the edges. With this in mind, the ruby api offers wrappers for situations where this becomes noticeable, e.g env.aliases will return a more ruby-like wrapper for the alias command that lets you do things such as env.alias.all, env.aliases.create and so on. In some cases (e.g. env.list_*), the wrappers add features (such as expanding strings) that aren’t found in the bash API via the wrapper.

A real world example

With that said and done, it’s time to look at a real world example. In this case, the most commonly-used example of the rvm ruby API – A use of passengers support for a config/setup_load_paths.rb file which lets passenger automatically load .rvmrc files. When a compatible ruby is detected, the file will automatically switch the gemset on the fly – In essence, letting passenger work with the one-gemset-per-application philosophy we advocate when dealing with rvm.

For references sake, the rvm portion of the code is:

if ENV['MY_RUBY_HOME'] && ENV['MY_RUBY_HOME'].include?('rvm')
  begin
    rvm_path     = File.dirname(File.dirname(ENV['MY_RUBY_HOME']))
    rvm_lib_path = File.join(rvm_path, 'lib')
    $LOAD_PATH.unshift rvm_lib_path
    require 'rvm'
    RVM.use_from_path! File.dirname(File.dirname(__FILE__))
  rescue LoadError
    # RVM is unavailable at this point.
    raise "RVM ruby lib is currently unavailable."
  end
end

Line by line, this code essentially:

  1. Checks that we’re loading it in an RVM ruby – rvm always sets the MY_RUBY_HOME environment variable when using wrappers and we ensure that “rvm” is part of said variables value.
  2. It begins a begin-rescue-end section of code to load rvm – Giving us a nice error message if rvm isn’t available.
  3. Based on my ruby home, We find the location of your rvm install (as rvm_path may or may not be set at this point).
  4. We add the rvm ruby lib directory to the load path
  5. We require the API

Up until this point, it is almost exactly like our original example. Where it differs is the next line:

RVM.use_from_path! File.dirname(File.dirname(__FILE__))

Knowing what I wrote about earlier, we know this is the same as:

RVM.current.use_from_path! File.dirname(File.dirname(__FILE__))

Which, if we look under the hood, does:

RVM.current.use! RVM.current.tools.path_identifier(path)

Expanding this again using what we learnt earlier, we know that RVM.current.use! will take a given ruby string (e.g. ree@rails3) and attempt to switch out the gemset when the ruby versions match. Continuing on, we know RVM.current.tools.path_identifier is roughly the same as RVM.current.tools_path_identifier – a line which takes a path and, taking into account .rvmrc files, returns the identifier (e.g. ree@rails3) we’d get if we had changed into the given directory from the command line.

Putting it all together, the ruby api essentially just finds out which identifier the given path should use (by loading a projects .rvmrc in the given environment), checks they’re for the same ruby install (to avoid issues with binary gems) and finally switches out the GEM_HOME and GEM_PATH variables for the current process, letting your application use a different gemset.

In short, under the hood it simple finds out the gemset details and updates your application to switch them out similar to how rvm would from the command line.

More examples

We’ve only covered the basics of of the ruby api – For the most part, everything implemented in the bash API is supposed to be (except where it lags behind in terms of updates) exposed via the Ruby API in a simple, consistent manner. In practice, this has primarily been used for things like infinity_test and various CI-related work which make working with multiple rubies easier from ruby applications.

I’d ultimately love to see it used more for tools built around rvm – e.g. a web interface for managing a servers system wide install and exposing it over HTTP. Lastly, because it’s written in Ruby, if you’ve ever wanted to contribute to rvm but have felt apprehensive due to the fact it’s written in shell script, the rvm ruby API is a good place to start.

Twitter

Great web stats at @petrescue , the driving force behind the rebuild of their systems by @frontiergroup . http://t.co/MTvfoxnU

@frontiergroup about 3 weeks ago #

Search Posts

Featured Posts

Categories

Archives

View more archives