Rails 4: `respond_to` always tries to render

There’s a curious quirk in the behaviour of the default Rails responder related to the redirect_to method.

I encountered this behaviour while teaching an Introduction to RubyOnRails class and one of my students was stuck trying to get a redirect working in their create action in a controller.

This behaviour isn’t a bug, it’s just not obvious and if you don’t know about it you can end up feeling very frustrated.

The specifics of this quirk are that if a view template is present then ActionController will always try to render it, even if the redirect_to method is called in the matching action.

So, when you redirect in an action, ensure that there is no matching view in app/views waiting to scupper your plans.

Keep Your Secrets Secret

Rails is well known for its convention over configuration approach to development and it is one that makes a developer’s life a little easier. There are times though, when you need some configuration in your app and Rails (until the official release of 4.1) doesn’t offer you any guidance as to how to do this.

Like a lot of things in Ruby, there are many ways to tackle this problem. A quick search on GitHub reveals lots of gems offering solutions to this. It’s worth checking this out so you can get a feel for how others have solved this and so form your own opinion about what is best for your situation.

Keep your secrets secret

I’d like to show you the method that I prefer, one that is well suited to a 12 factor approach favoured by platforms like Heroku. In particular, check out the ‘Store config in the environment’ concept.

At it’s simplest, we want to avoid hard-coding configuration values our app relies on so that we can deploy it to different environments easily.

The added benefit of this is that we keep our secrets, like our API keys, and database passwords, out of source control and safe from the prying eyes of malicious users.

Keep it simple with Ruby

If you looked through the list of gems on GitHub that can help you with your configuration then you will have noticed that a few of them favour storing values in a .yml file, similar to how Rails configures the database connection.

This can work fine and can be made to fit in with a 12 factor approach however, for me it adds some extra moving parts that we don’t need, eg. parsing a .yml file into an object that Ruby can use.

Or in the words of a popular configuration library, Configatron:

YAML is terrible and should be driven from the face of the Earth. Because of this Configatron V3 does not support it. Sorry.

Wherever I can, I prefer to keep things as uncomplicated as possible and go with a plain Ruby approach.

Hashr

We’re going to use a gem called Hashr, which gives us a nice integration with environment variables, meaning it will be very easy to configure on Heroku when we deploy it there.

So let’s get writing some code.

lib/config.rb

require 'hashr’

module YourApplication
  def self.config
    Thread.current[:config] ||= Config.new
  end

  class Config < Hashr
    extend Hashr::EnvDefaults

    define(
      ga: {
        ua: ’UA-1234’
      }
    )
  end
end

We have to nest the Config class within your application namespace so that it doesn’t collide with the Ruby core class of the same name.

We require the Hashr gem because at the point this file is loaded (see below) we can’t guarantee that this dependency has been loaded by bundler.

Next we set up a convenience class method in the app namespace for easy access to this config object. This is an optional step, as it just means you have a little less to type when reading config values elsewhere in your app.

Thread.current[:config] gives us access to a global variable for the currently running thread. We then store an instance of the Config object in there to avoid having to reinitialise it every time we need to read a value.

Our Config class inherits from the Hashr gem, which adds some extra methods to the Ruby standard library Hash class.

The only extra method you need to worry about right now is the define method, which you can see is used inside this class.

define allows us to setup a Hash that stores our configuration values in. You may be wondering why not use a Hash directly? Well, the main two benefits for me are the environment variable magic (see below) and access to the hash via methods, eg. Config.new.ga.ua.

Environment variables

extend Hashr::EnvDefaults adds the environment variable magic we need. This magic isn’t really that magic though, and consists of allowing an environment variable that matches a Hash key to overwrite it, eg. Config.new.ga.ua can be overridden by ENV['GA_UA'].

In the example above, I set a default value for my Google Analytics UA variable. This is just a placeholder value for use in the development environment as we don’t want to keep any sensitive configuration values in our source control.

For us to make use of this configuration object, we need to tell Rails about it. config/application.rb will look something like this:

require File.expand_path('../boot', __FILE__)
...

require File.expand_path('../../lib/config', __FILE__)

module YourApplication
  class Application < Rails::Application
    config.settings = YourApplication.config
    ...

Files in lib aren’t automatically required so we need to require the config file we just created in order for it to be available to us throughout the app.

With that done, we can now access our ga hash from the config object by calling YourApplication.config.ga.ua. Most likely this will be in a partial somewhere, app/views/shared/_google_analytics_js.html.erb:

<script type='text/javascript'>
  var ua = '<%= YourApplication.config.ga.ua %>';
  ... ga code here ...
</script>

Setting environment variables on Heroku

Now that we have a configuration object setup and we’re using the values in the app, it’s time to deploy things and get it working on production.

We have one final step before the code is deployed and that is to set our config values using environment variables on Heroku. One command should do it…

heroku config:set GA_UA=UA-12345-12 -a your-app-name-on-heroku

Once that’s done, you’re safe to deploy the new code to Heroku.

Get more articles like this about using Rails Like A Pro

Onboarding developers to your Rails app sucks

Have you ever asked someone else to help with your Rails app? Did you notice how painful it seemed for them to get everything working? Or how about contributing to someone else’s project? A bad setup experience can really suck away the motivation to help.

It usually goes something like this… you clone the repo from Github, look at the readme and realise it is still the default Rails template version. Ok, run bundle install, hopefully that goes well.

Next you try the database setup rake task but you’ve forgotten to put your details in the config file. Hopefully there’s a sample version to avoid the actual file being checked in to source control. If not, and you need to make a change, get ready for some annoying git stashing when it comes to pushing your code back.

What about those projects with a /db/migrate folder overflowing with migrations? Run rake db:migrate and hope they all still run?

Regardless of how much experience you have building apps with Rails, this is still a pain.

How did we end up like this?

Very often, the dependencies of your app evolve over time. You add a background worker to avoid a user having to wait for a process to complete, and then an A/B testing library or a feature flipper. Before too long there’s quite a list of dependencies that are not managed by any specific process.

The trouble is, tasks like creating and configuring these dependencies is often a one-time affair for you, well, once in your development environment and then once on your production server. Once done, it’s easy to forget that it’s a requirement for the app to work properly.

Automate it

The solution then, is to automate as much of this as we can. And we can automate the majority, if not all of it.

The easiest way to do it is to keep a bash script up-to-date with the steps required to get the app up and running and let it evolve alongside the app’s requirements.

Generally this is what I start with in bin/setup:

#! bin/sh

echo "Installing dependencies"
bundle install --quiet

echo "Preparing database"
rake db:setup

echo "All done. Run 'rails s' to start a server"

This will ensure my gem dependencies are up-to-date and my database is present and fully migrated. rake db:setup also runs the rake db:seed task, that populates the database from the db/seeds.rb code.

Make it idempotent

At this point, I’d like to recommend that you ensure your script can run in an idempotent fashion. Which is a succinct way of saying don’t overwrite things.

In order for this script to be useful and used by you, it shouldn’t overwrite or re-install things that are already up-to-date. Dependencies that haven’t changed don’t need to be re-installed and likewise, your db doesn’t need to be dropped and then created from scratch every time you run this script.

So, the script should aim to check what has been done so far and only perform steps that need to be run.

Fortunately, a lot of the system tools we use have this idea baked in. Bundler, for example, only updates your gems when a version has changed and you have asked for an update.

If you’re on a Mac, the brew command operates in a similar idempotent fashion.

Checking dependencies

As part of my setup script, I like to check for the presence of any dependencies that aren’t included in my app’s Gemfile. This generally is made up of databases and sometimes queue servers or a caching server.

Because we’re writing a shell script, we have all the power of the command line at our disposal and are able to make use of the which command for easy dependency checking.

if test ! $(which createdb)
then
  echo "You need to install PostgreSQL. If you use Homebrew, run:"
  echo "        brew install postgresql"
  exit
else
  echo "PostgreSQL found"
fi

I repeat that block for any other dependencies the app has.

Config files

Another step we can automate is to create local versions of our standard .yml config files. At a minimum this will require us to create config/database.yml.

It’s good practice to keep configuration files that may differ between developer machines out of version control. So, when starting a new project I will create a config/database.yml.example file with generic values, this gets committed to version control, and then let the setup script create my local version, which gets ignored by my .gitignore settings.

if test -f config/database.yml
then
  echo "Database config already set"
else
  cp config/database.yml.example config/database.yml
fi

Running the app with Foreman

Finally, the last common step we want is starting up all the services our app depends on. At the very least we want to fire up a web server. This is where we look to a great tool called Foreman.

Foreman allows us to define the processes our app needs in a Procfile and then manage these processes with a common set of commands, eg. foreman start and foreman stop.

We need to ensure that in the root folder of our app we create a Procfile:

web: bundle exec rails s 

This is the simplest Procfile we need.

It can also include other entries such as worker: rabbitmq-server. You can do anything that you would at the command line, so feel free to add switches for port numbers for example.

In order to add this to our setup script, let’s output a message that instructs the user how to start the app.

echo "Success. The app is installed. To view it in a browser, run:"
echo "  foreman start"

Summary / tl;dr

  • Automating your setup process will save time for you and anyone else who wants to contribute to your project.

  • Keep it current by updating it as your app changes.

  • Run it yourself, often.

  • Do it today.

Get more articles like this about using Rails Like A Pro

The Magic of has_many associations in Rails 4

If you’ve recently switched to Rails 4 or are just starting out learning to use Rails, then you may have come across some weirdness when trying to set a has_many association for real in one of your forms.

You see, in Rails 4, we got some improvements related to the security of our forms, in particular what parameters we’ll accept from a user submitted form. In previous versions of Rails, it was up to the developer building on top of the framework to implement this, usually using a mix of attr_accessible and slice on the params hash.

Then, there were some high profile security breaches related to the fact that developers weren’t actually doing this. And it was decided it was time to pull a solution for this into the core Rails project.

The Rails 4 solution is to use parameter whitelisting by default.

The downside of this means that lots of beginners don’t know about this; after all, when you’re learning Rails, there is a lot to cover and it can take a while to get to some of the less sexy aspects like security.

There isn’t a huge amount of documentation for this either, at least not for Rails 4. This means that people searching for info on this tend to get an out of date fix relating to Rails 3, which doesn’t work and leaves you feeling frustrated.

It makes sense for the framework to provide a sensible default that helps beef up the security of your app for you, without requiring much initial knowledge or time from the developer.

The documentation for how to use this seems buried within the Rails guides and the error messages you get are quite subtle.

This presents us with an opportunity to get familiar with a good pattern for tracking down bugs in our code. In this case, related to incorrect use of the framework.

A has_many association in a form

Suppose we are trying to model the following system for managing surveys. We have a survey and we have a user. A user can be invited to multiple surveys. So we start with code something like this:

class User < ActiveRecord::Base
  has_many :invites
  has_many :surveys, through: :invites
end

class Invite < ActiveRecord::Base
  belongs_to :user
  belongs_to :survey
end

class Survey < ActiveRecord::Base
  has_many :invites
  has_many :users, through: :invites
end

class SurveysController < ApplicationController
  respond_to :html

  def create
    @survey = Survey.create params(:user_ids)
    respond_with @survey, location: [:surveys]
  end
end

The problem with this code is that we haven’t provided any whitelist for the correct field, in this case user_ids.

Rails doesn’t raise an obvious error for this, like it would with other incorrect uses of the framework. Instead you will get a subtle error message appearing in the app logs, along the lines of Unpermitted params :user_ids.

It’s easy for this to go by unnoticed because the form will submit but the values will never get passed to your database. Usually when you have a bug in your code, it causes Rails to raise an exception or you get some kind of validation error on your object, however in this case you have to go digging to find out what happened. The beginning Rails developer can end up in a state of confusion, wondering why the value won’t save yet there’s no apparent error message.

Check your logs

Bear with me on this slight detour but this gives us an opportunity to talk about a useful debugging technique. Your application logs.

Take a look in log/development.log and you will see a lot of output. On Mac OS X you can fire up the console app to watch this file update live as you make requests in your app. Alternatively, in your terminal just type tail -f log/development.log and watch the output there.

What are we looking at? In this particular case, we performed an action in our app that didn’t have the expected result, so that’s where we start looking in our logs.

    Started POST "/surveys" for 127.0.0.1 at 2014-01-09 17:24:19 +0000
    Processing by SurveysController#create as HTML
        Parameters: {"utf8"=>"✓", "authenticity_token"=>"OCK399rbR0tkFLgO+7XJa9hbyJ9gKewT+aGxZR6qP0c=", 
        "survey"=>{"name"=>"test", "user_ids"=>["", "1", "2", "3"]}, "commit"=>"Create Survey"}
    Unpermitted params :name, :user_ids

Look for the action you just called and see if you find anything interesting. In our case, it’s the POST /surveys line we want and when we find it we discover an error message waiting for us.

So, what is the correct way to do this?

Every form field that you wish to save must be marked as safe to pass through to your database. Rails gives us a couple of methods on the params hash to do this.

Firstly, permit accepts a list of safe parameter names we are happy to pass through from the form.

Secondly, require allows us to raise an error where a parameter isn’t present.

In your controller, you can do this.

class SurveysController
  ...

  private

  def survey_params
    params[:survey].permit(:name, :user_ids)
  end
end

This would allow the name form field to be passed through to our database. This is progress but will still fail silently if you try to pass a list of ids like you would for a collection. This special case requires a slight change in our list of accepted parameters.

class SurveysController
  ...

  def survey_params
    params[:survey].permit(:name, user_ids: [])
  end
end

Now we’re in business. When passing an array from our form, we need to inform the whitelister that this is what we intended, otherwise it will only let through one of the following types String, Symbol, NilClass, Numeric, TrueClass, FalseClass, Date, Time, DateTime, StringIO, IO.

Check out the code for this Rails 4 has_many example on Github.

Don’t miss the next post on using Rails like a pro

Sign up to receive my regular newsletter and get tips and advice to help you go beyond the tutorials and really start using Rails to its full potential.

Can’t find the right tool for your job? Build it.

Have you ever come across a problem that you thought could be easily fixed by software but couldn’t find a tool to do it?

It can be a very frustrating experience. This tool should exist!

So, how hard could it be to build it yourself? After all, you’re not doing it with the hopes of going into the tech profession. It really is just to make stuff that makes your job easier.

You might work in a field that’s not directly related to tech and you don’t have access to that techy colleague who can whip something up for you. So what are your options?

Go looking for a developer on oDesk? This might work out for you. Don’t go into this without careful planning and clear idea of what you want, otherwise this will end up being a mess.

You could have a go at solving the problem yourself?

Before you dive headlong into figuring out which programming language you want to learn (spoiler alert: RubyOnRails), it’s worth investigating the tools available to you as someone without much (any?) coding experience.

So where do we start… as with so many things today, there’s usually a service that can help you out.

Automation as a Service (AaaS, now that’s a good acronym)

If you’re looking to automate a process, and a lot of software tools fall into this category, then your first port of call should be IFTTT and it’s business focused rival Zapier.

These services allow you to chain together actions on different web services based on a trigger you specify. A great example is to add a reminder to your phone telling you to take an umbrella to work when that day’s weather forecast is rain.

Or how about something more business related… send the responses from a form hosted on WuFoo to your Salesforce account as a new lead.

At this point, your problem might be solved. You can accomplish a lot by using web services as the building blocks of your tool.

However, if you need something a little more specific, read on…

Backend as a Service

Continuing the theme of leveraging existing services we arrive at BaaS.

There’s a whole raft of services offering a backend for your next project, accessed via a handy REST API. The 2 big uses cases for this are developing for iOS, where you need to store data beyond on a server but don’t want to (or can’t) build the server part yourself.

Secondly, if your experience lies in developing for the front end and you are pretty handy with Javascript, then this can be a great option for you.

Parse appear to be the leader in this market, but you could also check out Firebase, Kinvey and Kii.

If you fancy having a go at installing one yourself, there is Helios, an open source BaaS that you can deploy to Heroku and manage yourself.

Still not enough for you?

You’re still looking? Ok, I guess it’s time to bite the bullet and start learning to code. The question now is what language shall I use and where do I start?

You have a lot of options, so let’s narrow things down a little.

Here’s the big 4:

  • PHP. The workhorse of the web. Facebook uses it. Probably the most popular web language.
  • Java. Google use this for a lot of their stuff, they also built a framework for writing web apps in Java, it’s called GWT.
  • Python. Another favourite in the Googleplex. Python has a great web framework called Django.
  • Ruby. The goto language of many startups, primarily because of it’s web framework called Rails. Twitter was originally written in it.

Out of those options I always recommend Ruby, paired with the Rails framework, as people’s first step on the journey to learning to build web apps.

It’s a great language to learn, you can pick up great habits of software development that will make it easier for you to learn other languages, if you want to pursue it later.

But, the primary reason people love RubyOnRails is how quickly you’re able to build things with it.

Where to start with Ruby?

A key part of learning is to recognise what are the ways that you learn the best.

Most people find that a combination of visual and kinetic learning styles are most effective. So, for coding, watching someone doing something and then doing it yourself straight after, seems to be a good way to approach learning.

There are a lot of resources available for learning RubyOnRails at different levels of experience. In general, the community is great and very welcoming and helpful towards people new to the scene.

The thing about Rails is that it’s a framework that is built on quite a few different concepts and disciplines. Just by using it you will be exposed to Ruby, HTML, CSS, Javascript, a templating language to embed Ruby in HTML (ERB), SASS, Coffeescript, the request/response cycle, HTTP, REST, databases, SQL, automated testing and automated deployment.

Phew, that list is quite long and has a lot of acronyms. You don’t need to know all of that before you can build something. Just keep in mind that you will be learning more than just a single programming language when you build things on RubyOnRails.

Your first port of call should be Try Ruby. This will let you play with Ruby in your browser, without needing to install anything. Then, if you like learning from a book, have a read through Rails Tutorials. It’s free and covers a lot of ground. Also worth keeping an eye on is Learn Rails by Daniel Kehoe.

If you prefer a mentor based approach, then let me do some shameless self promotion and highlight my class Rails Kickstart. It’s a video based course, taking you over the basic building blocks you need to create your own apps with RubyOnRails, with access to support from an experienced Rails developer to help you when needed.

Beyond that, there are some great bootcamp classes, Web development immersive course at General Assembly (disclaimer: I teach in their London office sometimes), Maker’s Academy and Dev Bootcamp. These bootcamps require quite an investment of your time, so they only make sense if you’re looking to make a career of this.

So, what are you waiting for? Get building.

Get regular tips to help you learn how to build your app with Rails

* indicates required

Looks interesting. Designing for email can be such a pain. Hopefully this makes it less painful.

Installing Rails is not for beginners

You’ve seen the tutorials about how easy it is to build a RubyOnRails app. Those screencasts have been blowing your mind. Type a few lines in the terminal…

gem install rails
rails new app_name
rails g scaffold posts

… and ‘hey presto’, there’s the beginnings of the next Tumblr. At this point, as a beginner programmer, you’re feeling pretty inspired by the possibilities that lie before you.

Faithfully, you type out the lines you read in the tutorial and then this happens…

    Building native extensions.  This could take a while... ERROR:  Error installing rails:     ERROR: Failed to build gem native extension.

That looks scary. You Google it and find the solution. Install Xcode command line tools. 3gb download? Ok, so you go and read up on the tutorials again while you wait.

Finally, everything is installed. Time to get writing some code.

Hang on, do you have a text editor? No. Ok, just quickly go download one.

And on the rabbit hole goes. At some point you will be able to start coding but you might have lost the will to try in the process.

As someone wanting to learn programming, particularly if you want to build for the web, RubyOnRails is a brilliant place to start.

Unfortunately, getting your computer to a place where you can actually write and run code can be real pain in the ass.

Your first interaction with Rails shouldn’t be installing dependencies and getting a development environment working. I’m a firm believer that you need to get excited about what you can do with Rails before you should persevere with learning how to set up your environment properly.

Fortunately, there is an app for that… actually there are a few.

My favourite being Nitrous.IO. For your first time with Rails, this is going to make your life so much easier.

Sign up for a free account, create a box setup for Rails and then everything you need to get started is installed for you.

I recommend it whenever I teach people to code with Rails now, as it’s a great base for everyone to start with. After all, you don’t want to learn to install software, you want to learn to build a software product.

  • Also worth checking out in the online coding department… FriendCode and Koding.

Get regular tips to help you build your app with Rails

* indicates required

Get started building your next app with RubyOnRails.

thoughtbot:

Do you realize how much time you’ve spent running bundle install after cloning a new repository?

sword fighting

No more sword fighting! Bundler 1.4.0 adds support for parallel installation. You can pass in --jobs=SIZE (or -jSIZE) as a parameter to bundle install (or bundle). I recommend setting…