Rails, Paperclip, Custom Interpolation

To allow custom interpolations in the PaperClip :path designation, add the following to your config/initializers/paperclip.rb file:

Paperclip.interpolates :custom_field do |attachment, style|
  attachment.instance.custom_field
end

 
Where :custom_field is whatever field associated with your attachment model you’d like interpolated in your path.

Rails 4, AWS Elastic Beanstalk, and RDS

This guide shows you how to configure a Rails 4 app with AWS’s elastic beanstalk and RDS.

First, install the elastic beanstalk command line tool on your local development box:

$ sudo apt-get install git 
$ sudo apt-get install python-dev
$ curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py"
$ sudo python get-pip.py
$ sudo pip install awsebcli

 
Next, initialize a GIT repository for your project if you haven’t already:

$ git init
$ git add .
$ git commit -am "Initial Commit"

 
Before initializing your Elastic Beanstalk instance, you may need to configure a new IAM user with the appropriate permissions. If you already have an appropriate user, skip to the “Initializing Elastic Beanstalk” section below, otherwise, do the following:

Creating a new IAM user to manage your Elastic Beanstalk

Because Root AWS API keys are deprecated, it is recommended that you create a new IAM user and group for your Elastic Beanstalk environment (to get the Access Key ID and Secret Access Key necessary to run eb init). To do this, go to:

https://console.aws.amazon.com/iam/

Click “Users” in the main left menu and select “Create New Users” in the main top menu.

Enter the username for your beanstalk user and hit “Create” in the bottom right corner. Make sure “Generate an access key for each user” is selected prior to clicking “create”

After clicking create, you will receive a success message and the option to “Show User Security Credentials”. Click that and save the Access Key ID and Secret Access Key in a secure location, then click the “close” button in the bottom right of the dialog.

With the user created, click “Groups” in the main left IAM menu and click “Create New Group”. Skip the “Attach Policy” section, then click “Create Group” in the bottom right of the dialog.

After the group is created, click its name and scroll down to find “Inline Policies”. Click the “Inline Policies” box and then click the “Click Here” link to create a new policy. In the next dialog click “Custom Policy” and use the following to define your policy’s permissions.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "elasticbeanstalk:*",
        "ec2:*",
        "elasticloadbalancing:*",
        "autoscaling:*",
        "cloudwatch:*",
        "s3:*",
        "sns:*",
        "cloudformation:*",
        "rds:*",
        "iam:AddRoleToInstanceProfile",
        "iam:CreateInstanceProfile",
        "iam:CreateRole",
        "iam:PassRole",
        "iam:ListInstanceProfiles"
      ],
      "Resource": "*"
    }
  ]
}


 
After successfully creating the new inline policy, click "Add Users to Group" and choose the newly created user and submit.

You now have a user capable of managing a full EC2 / S3 / RDS application via Elastic Beanstalk.

Setup Rails 4 to use RDS

Before creating your Elastic Beanstalk environment, let's configure the application's database configuration to handle RDS.

First, Open your Rails config/database.yml file and add the following for your production database:

production:
  adapter: mysql2
  encoding: utf8
  database: <%= ENV['RDS_DB_NAME'] %>
  username: <%= ENV['RDS_USERNAME'] %>
  password: <%= ENV['RDS_PASSWORD'] %>
  host: <%= ENV['RDS_HOSTNAME'] %>
  port: <%= ENV['RDS_PORT'] %>

 
And be sure to add the mysql gem to your Gemfile (in the production group only if desired):

group :production do 
  gem 'mysql2'
end

 
This is everything you need to configure your Rails app to use RDS on Elastic Beanstalk. Be sure to bundle install the mysql2 gem if you haven't already.

Initializing Elastic Beanstalk

To initialize your elastic beanstalk environment, run the following command in your local CLI:

$ eb init 

 
This will ask you for some basic information, including the region for the Elastic Beanstalk profile (defaults to Oregon), along with your AWS access key ID and AWS Secret Access Key (created above).

It will also ask you what platform you require. Typically, selecting the default is fine here (at the time of writing, it is configured to 64bit Ruby 2.2 with Puma).

This command will also update your .gitignore file. Commit all changes and continue.

Now, to create the Elastic Beanstalk environment and associated resources (EC2 and RDS), run the following:

$ eb create your-apps-name --database

 
A complete list of 'eb create' options can be found here: http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/eb3-create.html

Note: Without the '--database' flag, the system will assume you're not using an RDS database and will simply skip configuring it for you. With the '--database' flag, it will ask you for the username and password for the database.

After completing the RDS configuration questions, the system will go about installing all of the necessary resources. By default, this is a load balancer, a series of watchers, a t1.micro EC2 instance and an RDS database.

If the create command times out in the middle of the process, don't worry, it is still running. To see the current status of the command, run the following in your CLI:

$ eb events -f

 
This will give you a live stream of the current status.

Once the eb create command is completed, it will provide your environment location, something like:

your_app.elasticbeanstalk.com

 
If you're using Rails 4 and you go to the environment location (above) in your web browser, you'll run into the most ridiculously unhelpful error:

A really lowlevel plumbing error occured. Please contact your local Maytag(tm) repair person.

Update: this issue can also take the form of a 502 bad gateway error (nginx)

At this point, you may want to throw your keyboard at the window and just say "Welcome back Heroku" -- but don't, not yet. To finalize your new Rails 4 Elastic Beanstalk configuration, run the following commands in your local CLI:

$ rake secret

 
This will create a nice 64 character string to use as the rails 4 secret token. To set this as an environment variable in your new Elastic Beanstalk application, do the following in your CLI:

$ eb setenv SECRET_KEY_BASE=your-secret-key-generated-above

 
Once the process is complete, go back to your environment location in your browser, and everything should look good.

At this point, you can begin/continue developing your application normally. Any time you want to publish your changes to the Elastic Beanstalk environment, just run:

$ eb deploy

 
And the new code will be deployed for you.

The Elastic Beanstalk App and associated EC2/RDS resources are not showing up in the AWS web console

If you're running into this issue, make sure the current AWS region (upper right corner of the AWS console) is set to the region you requested in 'eb init'. If it is not, the resources will appear to never have been created.

Resolve Net::HTTPBadResponse: wrong status line

In Ruby/Rails, if you’re running into the following error:

Net::HTTPBadResponse: wrong status line

When attempting to post data to a secure (https) url, with something similar to:

Net::HTTP::post_form("https://www.example.com",{})

 
Then you can rewrite your request to avoid the exception like this:

url = URI.parse("https://www.example.com")
http = Net::HTTP.new(url.host,url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url.path,{})
request = http.request(request)

 
After which, you can access the request response in the same way as always.

Cron Job: Run rails rake task in shell script

To run a rake task within a shell script using a cron job, do the following:

First, specify the shell at the top of your .sh script

#!/bin/sh

 
Then, change your directory to your rails application in your .sh script

cd /home/user/app/current

 
Now, you need to manually define your PATH within the script:

PATH=/your/paths:/etc/etc

 
To see your user’s PATH, do the following in your terminal: echo $PATH

Now, assign your rake executable path to a variable in your script:

RAKE_PATH=/home/user/.rvm/rubies/your-ruby/bin/rake

 
To see where the rake executable is located, do the following in your terminal: which rake

Finally, to execute your rake task, do the following:

RAILS_ENV=production $RAKE_PATH your_task

 
So, the final version of your .sh script would look something like this:

#!/bin/sh
cd /home/user/app/current
PATH=/your/paths:/etc/etc
RAKE_PATH=/home/user/.rvm/rubies/your-ruby/bin/rake
RAILS_ENV=production $RAKE_PATH your_task