Why do this manually?

I am aware that there are PaaS out there (Heroku, EngineYard, DotCloud) that allows developers to deploy Rails app easily without requiring you to understand what’s going on behind the scene. But, I still believe that it’s nice to know how to manually set up your own server and deploy your code manually in the cloud (this time, we are going to use AWS EC2). This is not to say that I dislike PaaS. In fact, I really like them and I think they’re really great solutions that save a lot of developers’ time.

I currently work for a company that does not use any of the aforementioned PaaS. I often have to write my own script or deploy tasks that would start/manage the application and whatnot. Although doing all this is more tedious, I like the visibility and the explicitness that it provides. Not too much magic, just plain old manual setup.

Ruby gems, DB, and other things that I will use in this post:

  • ruby-2.0.0-p353
  • Rails 4.0.1
  • EC2
  • MySQL RDS
  • Git
  • Passenger

New Rails App (Feel free to skip this)

I am not going to do too much for this part. All I want to do is create a new Rails application and change the root page to show a static text (Hello World). I am going to outline the steps but you should be already familiar with this process.

Open up your terminal and go to your project folder. Mine is ~/workspace. Create a new Rails project (we are going to call it ‘blogapp’) by running the following:

cd ~/workspace
rails new blogapp

Now, I am going to create a new git repository for this new app and store it in BitBucket (feel free to use GitHub).

cd ~/workspace/blogapp
git init
git remote add origin ssh://git@bitbucket.org/denniss/blogapp.git
git add . && git commit -m "First commit"
git push origin master

Next, we are going to create a controller and a view and have the routes specify the root to point to the index page.

rails generate controller pages index

Find the index.html.erb that is generated by the last command and add a Hello World to it. Go to your routes.rb and change the root to point to pages#index.

#routes.rb
Blogapp::Application.routes.draw do
  root "pages#index"
end
#pages_controller.rb
class PagesController < ApplicationController
  def index
  end
end

Try running your server locally and see that it works. Just for sanity check, this is what I see.

img

Using Passenger

Although WEBrick will work just fine for development, we are not going to use it for production environment. We want to use a web server that is more scalable and production-ready. You have several choices (Unicorn, Puma, Passenger), but, this time, we are going to use Passenger.

Add the passenger gem to your Gemfile

#Gemfile
#...
gem passenger
#...

And run bundle install on your project directory so that it fetches the newly added gem.

bundle install

Now try running your app using Passenger by running

passenger start

You should see something like this in the Terminal

img

Go to localhost:3000 again on your web browser and you should be able to see your hello world page.

Remember to update your git repo

git add .
git commit -m "Add passenger gem for production"
git push origin master

Continue to part 2

The Problem

I was working on implementing a new API endpoint in Go that renders a list of users in JSON. The idea is simple. Grab the users from DB, convert them into struct representation, marshall the array to JSON and return the JSON in the response body. Problem arises when I find out that one of the columns in the users table is a nullable varchar.

Before going to the Go implementation, I am going to digress a little. For those of you who are familiar with Rails, what I am trying to do is equivalent to the following:

User.all.to_json

The code above is very simple and quite magical. A lot of things are taken for granted here. Doing the same thing in Go is not as simple and requires a 2 step process: Convert the user entry from DB to structs and convert the structs to JSON string.

My users table definition looks like this in DB

id          `int`
first_name  `varchar(255)`
middle_name `varchar(255) DEFAULT NULL`
last_name   `varchar(255)`

And my struct definition for User looks like this in Go

type User struct {
   Id           uint32  `json:"id"`
   FirstName    string  `json:"first_name"`
   MiddleName   string  `json:"middle_name"`
   LastName     string  `json:"last_name"`
}

If you cannot see the problem already, think about what would happen if a user does not have a middle name (A NULL value in the database for middle_name attribute). This means that User instance would have a null value for its MiddleName field in Go-land. BEEEP! null for string field? Is that possible in Go-land? Nope.

Partial Solution

The database/sql package has a solution to this by providing a struct called NullString. sql.NullString has a boolean field called Valid that, when false, deems the value as null. Definition of NullString is as follows:

type NullString struct {
   String string
   Valid  bool // Valid is true if String is not NULL
}

So, to leverage this struct, I change the User definition to the following

type User struct {
   Id           uint32          `json:"id"`
   FirstName    string          `json:"first_name"`
   MiddleName   sql.NullString  `json:"middle_name"` //Changed
   LastName     string          `json:"last_name"`
}

Sweet! Now, conversion from DB-land to Go-land works! You can check if MiddleName is null by looking at the Valid field. If Valid is true, you can look at the value by accessing its String field. So far, so good and we are done with the first part (converting DB entry to Go struct).

Problem #2

Next, we want to be able to convert the user instance in Go-land to JSON string. Without doing anything else, if we try to convert (using json.Marshall) with the current struct definition, we are going to get something like this in JSON.

{
    "id" : 1,
    "first_name" : "Dennis",
    "middle_name" : { "String" : "Ahoy?", "Valid" : true }, //JSON representation of sql.NullString
    "last_name" : "Suratna"
}

or, when middle_name is null in database

{
    "id" : 1,
    "first_name" : "Dennis",
    "middle_name" : { "String" : "", "Valid" : false },
    "last_name" : "Suratna"
}

How did this happen? Well, take a look at how sql.NullString is defined and think how it would be represented in JSON. The middle_name field is marshalling the sql.NullString value to JSON. This is expected but not something that we want. What we really want is something like this:

{
    "id" : 1,
    "first_name" : "Dennis",
    "middle_name" : "Ahoy?",
    "last_name" : "Suratna"
}

or, when middle_name is null in database

{
    "id" : 1,
    "first_name" : "Dennis",
    "middle_name" : null,
    "last_name" : "Suratna"
}

Solution using MarshalJSON

I tried a couple workarounds but I ended up implementing a custom MarshalJSON for the User struct. Here is the implementation:

func (u *User) MarshalJSON() ([]byte, error){
    middleNameValue, err := u.MiddleName.Value()

    if err != nil {
        return nil, err
    }

    var middleNameJsonString string

    if middleNameValue == nil {
        middleNameJsonString = "null"
    } else {
        middleNameJsonString = fmt.Sprintf("\"%s\"", titleValue)
    }

    jsonString := fmt.Sprintf("{\"id\":%d,\"first_name\":%s,\"middle_name\":%s,\"last_name\":%s}", u.Id, u.FirstName, middleNameJsonString, u.LastName)

    return []byte(jsonString), nil
}

I have to admit that this is not the cleanest solution (and probably not the best). However, it is a working one and it renders the JSON properly. If you have a better solution to this, please let me know!

By the end of this post you are going to be able to use IntelliJ and leverage its cool features to work with your Go projects.

Install Golang with Homebrew

1 brew install go --cross-compile-common --with-cgo --use-gcc

Install IntelliJ IDEA 13

At the time of this post’s writing, IntelliJ 13 is still in Early Access Program (EAP). Here is the download link:

http://confluence.jetbrains.com/display/IDEADEV/IDEA+13+EAP

Install golang.org support plugin

Once you have installed IntelliJ, go to preferences ( Command + , ) and go to the Plugins tab. Here, you will see all the available plugins that can be enabled/disabled immediately. The one that we need, however, has to be downloaded.

Plugins Window

Click on Browse repositories the middle button at the bottom of the Preferences panel. This will open up a panel that allows you to install third-party plugins for IntelliJ. Look for golang.org support plugin.

Browse Repositories

Once you have highlighted the row as shown as above, click the download button (top left corner, the second button). Once you have installed this, restart IntelliJ.

Configure Go SDK in IntelliJ

Open the Project Structure Panel (Command + ;).

Project Structure

Select the SDK tab, click the + button to add a new SDK and choose Go SDK

Browse Repositories

Once you click Go SDK, you will be prompted to locate the Go folder. If you installed Go using Homebrew, you should be able to change directory to (In Finder, you can press Cmd+Shift+G to open up panel to go to folder)

/usr/local/Cellar/go/1.1.2/libexec

(your version may vary), and click ‘choose’

SDK

That’s it! You can now start your Go project by going to “File > New Project”

McAfee SECURE - Shopper Identity Protection