Blog

Running an R Script From a Ruby on Rails App

Featured in Ruby Weekly

Introduction

Have you ever thought about using R (the programming language) to run some analyses using data from a Ruby on Rails application? This tutorial will provide step-by-step walkthrough on how to connect a simple Rails app to R.

I recently needed to run some complicated statistical analyses on data generated by a Rails application. This analysis was important for my client’s product – they had even hired a Ph.D mathematician to provide guidance! Our mathematician recommended we use a particular model to analyze our data. While she was familiar with using a desktop-software version of this model, I needed a open-source, programmable solution. Luckily, we found an R package! But how could I use an R package in a Rails app? I did my best googling and stackoverflow-ing for a solution, but everything I could find was about 4 years old. Not going to cut it. Finally, I sat down and spent some time figuring it out. And now I’m sharing it with you!

Pre-requisites

This tutorial assumes you have a basic understanding of Rails. I’m not going to assume you know much (or anything, really!) about R, so we’ll cover some basic commands you’ll need as we go. I’m also assuming you’re developing on a Mac. If you develop in a different environment, you might hit some speedbumps along the way. If so, try looking for documentation specific to your situation!

What We’ll Cover in This Tutorial

In this tutorial, we’ll use a very simple Rails app to create a rake task that runs a script in R. Because it’s a bit unusual, we’ll first walkthrough how to run an external ruby script from a Rails app. We’ll then translate that knowledge to running a script in R! The final step is to use a package for R to do some more complicated analyses.

Don’t care to type along, but want to see the final product? Check out the Test-R GitHub repo

Pre-learning Setup

Before we can start our learning, we need a basic rails app to play with. The guts of our app will really be to run a rake task, and we’ll make a simple view that runs our script just for giggles. To make your rails app, run

rails new testing-r-app

Calling to a Ruby Script from a Rake Task

I’m a fan of breaking things down into tiny, solvable pieces. Let’s start with a simple rake task that first talks to something we’re familiar with: ruby! In /lib/tasks make a new file called script_runner.rake. Inside, create a simple rake task:

desc "Runs an external ruby script"
task :run_ruby => :environment do
    puts "running ruby!"
end

In /lib, lets make a new folder to organize our fancy external scripts… I’ll call mine external_scripts. Inside of /lib/external_scripts, make a new file called ruby_script.rb. This will be the ruby code that we’ll run from our rake task. What will our ruby script do? Well, I’m not feeling that creative yet, so let’s start with it having this content:

puts "%%%%%\nhello im a script\n%%%%%"

Boooorrrring, I know, but let’s get it working! Back in your rake task, run_ruby, we need to do a few things:

  1. Specify where to find our new script.
  2. Run that script.
  3. Do something so that we know the script ran successfully.

We can accomplish these things by adding the following code to the run_ruby rake task:

filepath = Rails.root.join('lib', 'external_scripts', 'script.rb')
output = `ruby #{filepath}`
puts output

In the first line, we specify our file location. Simple enough. The second line is where it gets interesting. We call ruby #{filepath}. You can imagine that if you were typing into your terminal, this is exactly what you would type to run a ruby file. But in this case, we wrap it in “backticks”. These backticks tell ruby to execute something (there are a few other ways to make this same thing happen, too). Finally, the last line of our rake task takes the results of running our script and prints them to the commandline. Boom! We did it!

A quick note: Obviously, you probably don’t want to print things to a terminal from a Rails app. This was just a quick way to explain how to interact with an external ruby script.

Writing an R Script

Now that we’ve got our ruby script rake task all wired up and working, let’s start working towards our goal of running an R script via our Rails app. Again, we’ll take this step by step and make sure we have all of the pieces in place.

Install R locally

Before you can run R, you need to install it! I used homebrew to install it quickly:

brew tap homebrew/science
brew install r

Once the install finishes, let’s test it to make sure it works. To open the R CLI, just type R in your terminal. It should load an R workspace where you can play around if you like. If that’s all good to go, let’s go back to our Rails app.

“Hello World”

Make your new R file. Create a new file named hello_world.R inside of your /lib/external_scripts folder. Inside that file, you want to put the following code:

cat("Hello WoRRRRRRld")

This line should print our “Hello World” statement. In R, cat() works similarly to puts in ruby, although the syntax of how you interpolate variables is different.

The next step is to create our new rake task. In your script_runner.rake file, create a new rake task called hello_world_r:

task :hello_world_r => :environment do
    puts "running R!"
    filepath = Rails.root.join("lib", "external_scripts", "script.R")
end

Again, we need to start with specifying our filepath. Following what we know from our ruby script, we next need to find a way to run a bash command from the rake task to read and execute the script. Add the following lines to your rake task:

output = `Rscript --vanilla #{filepath}`
puts output

What are we doing here? Wow! Try it out! You should see it print our “Hello World” message. You just did it! You just ran an R script from Rails.

Passing in Arguments

Ok, so running an R script with no inputs and a silly output isn’t exactly realistic, so let’s kick the complexity up a notch. Let’s pass in some arguments. This is actually super simple. In your hello_world rake task, update the Rscript line to look like:

output = `Rscript --vanilla #{filepath}  'Pippi Longstockings'`

Now, update your hello_world.R file:

args = commandArgs(trailingOnly=TRUE)
cat("Ahoy there,", args)

Let’s walk through this code. commandArgs is a way of accessing any arguments you’ve passed into the script. By adding trailingOnly=TRUE, we’re saying we only want what’s interpreted as arguments – otherwise we’d get the filepath, too.

Run your rake task! You should see “Ahoy there, Pippi Longstockings”. Hooray! BONUS POINTS: can you pass a variable into your rake task, and pass it through to your new R script?

Using an R package in Your Script

We’ve mastered inputs and outputs between Rails and R. Now let’s figure out how to use a package in R to do work that’s a little more complicated – after all, you’re probably using R because you need to do something complex.

In R, packages are like gems in ruby. There are lots of different packages available. If you’re used to ruby you’ll find documentation of R packages, well, a bit different. We’re going to use a simple library to make it easy to demonstrate how to hook the pieces together, but keep in mind that there are some really great packages out there.

Today, we’re going to use the stringr library. Check out the documentation for stringr (it’s a PDF). Stringr let’s you do some basic pattern-matching of strings. We’re going to use the str_detect method, which takes in a string and a regex pattern, returning TRUE if the pattern matches and FALSE if it does not. Because it can take an array, we can use this method to find the subset of an array that matches the pattern, as well as the subset that does not match.

Installing a Package for R

Installing our stringr package is easy. In your terminal, go into the R CLI (type R), and then type:

install.packages('stringr')

You’ll be prompted to choose a mirror from which to download the package.

We’ll need to make a new R script to use our package. But first, let’s make our rake task really quickly. In your rake file, add this rake task:

task :run_r => :environment do
  puts 'running R!'

  filepath = Rails.root.join('lib', 'external_scripts', 'script.R')

  greetings = [
    'ARRRGH ME MATEYS',
    'Why hello, old chap!',
    'Hollaaaa!',
    'Hello, is it me you\'re looking for?',
    'Avast! Ye ARRRE so smart.',
    'Shiver me timbers this is a gRRReat tutorial!'
  ]

  output = `Rscript --vanilla #{filepath} #{greetings}`
  puts "Here's the output:\n #{output}"
end

We’re following the same patterns we have before:

  1. Specify a filepath.
  2. Specify an Rscript with the filepath and arguments to be run with backticks.
  3. Print our output to the terminal.

Ok, let’s go write our R code. In /lib/external_scripts, make a script.R. Inside it, place this code:

library('stringr') #1
args = commandArgs(trailingOnly=TRUE) #2
isPirateSpeak = str_detect(args, "[RRR]") #3
cat("\nWhat do pirates say? \n", args[isPirateSpeak]) #4
cat("\nWhat do non-pirates say?\n", args[!isPirateSpeak]) #5

In this code we:

  1. Load the stringr library via the library('stringr') call.
  2. Save our arguments (the greetings) we’ve passed in as a variable.
  3. Run our greetings through our string matcher from the stringr library to see if each one contains “RRR”.
  4. Print out the matches.
  5. Print out the non-matches.

Run your rake task and see what you get! Now you, too, know how to speak like a piRRRate!

Last Thoughts

What could you do with this? Well, perhaps you have a complicated statistical analysis to do on your data, and R has the best (or only!) package available for automated open-source analysis. This was the problem that drove me to write this!

Want to see my code? Check out the Test-R GitHub repo.

Was this useful to you? I’d LOVE to know if others are using R with their Rails app, or at least considering it. Drop me a comment below!