Tag: Rails


RailsConf 2015 Recap

by Alex Wood | on | in Ruby | | Comments

Recently, Trevor, Loren, and myself from the AWS SDK team attended RailsConf in Atlanta. We had a great time at the conference and enjoyed connecting with many of you there.

Our Rails on Amazon Web Services Workshop

At RailsConf, we ran a workshop called Deploy and Manage Ruby on Rails Apps on AWS. It was an amazing experience for us, with attendees of all experience levels gettings hands-on experience not only deploying to AWS, but learning about the tools we’ve made to help make integrations easier.

For those of you who could not make it, you can still give this workshop a try!

  • Detailed step-by-step instructions, the same as we provided to attendees, are available here.
  • You can also follow along with the presentation recording on YouTube.
  • Code for the sample app is available on GitHub.
  • If you’d like to try using Amazon Relational Database Service instead of using AWS OpsWorks managed MySQL, you can reference our blog post on that topic as well.

Continuing the Conversation

We hope to see more of you on the conference trail again soon! Apropos of this, it is worth mentioning that AWS re:Invent registration is open at the time of writing. We will be there, and we hope to see you there!

Announcing the aws-sdk-rails Gem

by Alex Wood | on | in Ruby | | Comments

With the release of V2 of the AWS SDK for Ruby, we’ve received customer feedback asking for support for the Ruby on Rails integration features provided by V1 of the SDK.

Today, we’re excited to announce the release of the aws-sdk-rails gem, available now via RubyGems and, of course, on GitHub.

To get started, add the aws-sdk-rails gem to your Gemfile:

gem 'aws-sdk-rails', '~> 1.0'

ActionMailer and Amazon Simple Email Service (SES)

The gem will automatically configure Rails to include an :aws_sdk delivery method for ActionMailer, that uses Amazon SES as a backend. It is simple to configure Rails to use this delivery method:

# config/application.rb
config.action_mailer.delivery_method = :aws_sdk

The aws-sdk-rails gem will use the AWS SDK for Ruby V2’s SES client automatically for any mail delivery event.

Logging

The gem will automatically wire the AWS SDK for Ruby’s logger to use Rails.logger by default.

You can customize the SDK log level and an optional log formatter in a config initializer:

# config/initializers/aws-sdk.rb
# log level defaults to :info
Aws.config[:log_level] = :debug

It is important to understand that all SDK log messages are logged at the same log level. Why is this important? When you set the Rails log level, you’re muting all log messages below that log level. So, if you want to, for example, only see SDK log messages in development, you might set the SDK log level to :debug as shown above, and set the Rails logger to show debug in development.

Credentials

The AWS SDK for Ruby will attempt locate credentials by searching the following locations:

  • ENV['AWS_ACCESS_KEY_ID'] and ENV['AWS_SECRET_ACCESS_KEY']
  • The shared credentials ini file at ~/.aws/credentials
  • From an instance profile when running on Amazon EC2

If you need to manually configure credentials, you should add them to your initializer:

# config/initializers/aws-sdk.rb
Aws.config[:credentials] = Aws::Credentials.new(access_key, secret)

Learn more about credentials in the AWS SDK for Ruby V2.

Never commit your credentials to source control. Besides being a security risk, it makes it very difficult to rotate your credentials.

Available Now

The aws-sdk-rails gem is available now.

As always, we’d love to hear your feedback, and welcome any Issues or Pull Requests at the aws-sdk-rails GitHub repo.

Caching the Rails Asset Pipeline with Amazon CloudFront

by Alex Wood | on | in Ruby | | Comments

Amazon CloudFront is a content delivery web service. It integrates with other Amazon Web Services to give developers and businesses an easy way to distribute content to end users with low latency, high data transfer speeds, and no minimum usage commitments.

Ruby on Rails introduced the asset pipeline in version 3.1. The Rails asset pipeline provides a framework to concatenate and minify or compress JavaScript and CSS assets. It also adds the ability to write these assets in other languages and pre-processors such as CoffeeScript, Sass and ERB.

With CloudFront’s support for custom origin servers, and features of the Rails asset pipeline, building a CDN for your static assets is simple. In this blog post, we will show you how to set this up for your environment.

Do You Have Geographically Diverse Users?

Amazon CloudFront provides 52 (as of when this was written*) edge locations around the world. Your static content can be cached by these edge locations to reduce the latency of your web application. Additionally, this can reduce the load on your app servers, as it limits the number of times your app server needs to serve large static files.

* See the current list of edge locations here.

Prerequisites

You should be able to deploy your Ruby on Rails application to the Internet, and you should know the hostname or IP address for where your application is hosted. If you have followed along with the series and deployed our sample application on AWS OpsWorks, you can complete this tutorial. If not, consider trying out a deployment first.

Creating a CloudFront Distribution

First, we will create a new CloudFront distribution that uses our app as the custom origin. From the Amazon CloudFront console, click Create Distribution. Under "Web", click Get Started.

Within this form, call the Origin ID "Rails App Server", and for the Origin Domain Name, we will point to the URL of our Rails application. Here is how:

  • If you have a domain name (e.g., "www.example.com"), then use that.
  • If not, you should use as stable of a hostname as possible. For example, the hostname of your ELB instance, or at least an Elastic IP. For demonstration purposes, the public host name of your app server instance will also work.

If you’re using something other than a domain name, don’t worry, you can change the origin address later if you need to. All other options can be left at their default values, though you can turn on logging if you want. We aren’t going to talk about using your own domain for the CDN just yet. Once you have your origin options set, click Create Distribution.

Configuring the Ruby on Rails App to Use CloudFront

Using CloudFront as the asset Host for your static assets is truly a one line change.

In config/environments/production.rb:

config.action_controller.asset_host = ENV['CLOUDFRONT_ENDPOINT']

This tells Rails to use your CloudFront endpoint as the hostname for static assets. Your endpoint hostname will be specified in a host environment variable.

To pick up that change if you’re following along at home, go in to the OpsWorks console and edit your app:

  • Under "Application Source", point to the cloudfront branch.
  • Add a new environment variable pair:

    • Key: CLOUDFRONT_ENDPOINT
    • Value: The URL of your CloudFront endpoint, available in the CloudFront console. For e.g., "lettersandnumbers.cloudfront.net"
    • You do not need to "Protect" this value.

Now, deploy your app! You do not need to run a database migration.

How It Works

While we wait for the deployment to complete, how does all of this work?

If you look at the page source of our application before adding the CloudFront CDN, you’ll see lines like this:

<link data-turbolinks-track="true" href="/assets/application-0f3bf7fe135e88baa2cb9deb7a660251.css" media="all" rel="stylesheet" />
<script data-turbolinks-track="true" src="/assets/application-2ab5007aba477451ae5c38028892fd78.js"></script>

Those lines are how the page is including your application.css and application.js files. In app/views/layouts/application.html.erb, they correspond to these lines:

<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>

In turn, these include statements source from app/assets/stylesheets/application.css.scss and app/assets/javascripts/application.js. If you run the command rake assets:precompile, these files will be compiled and a fingerprint will be added to the filename. For example, I ran rake assets:precompile and the following files were generated:

  • public/assets/application-f3fd37796ac920546df412f68b0d9820.js
  • public/assets/application-68a6279b040bd09341327b6c951d74bc.css

The fingerprinting is a big part of what makes all of this work so smoothly. Let’s take a look at the page source after our latest deployment:

<link data-turbolinks-track="true" href="http://lettersandnumbers.cloudfront.net/assets/application-bfe54945dee8eb9f51b20d52b93aa177.css" media="all" rel="stylesheet" />
<script data-turbolinks-track="true" src="http://lettersandnumbers.cloudfront.net/assets/application-4984ddfbabfbae63ef17d0c8dca28d6c.js"></script>

You can see that we are now sourcing our static assets from CloudFront, and that nothing broke in the process. You can also see the compiled assets with fingerprints added to the filenames. When we loaded the page, the stylesheet_link_tag and javascript_include_tag used our asset host as the host, adding the expected asset filenames to the end of the hostname. When CloudFront received the request, these assets did not exist in the cache, so it forwarded the request to the Rails server, which served the files to CloudFront, which cached the files and sent them to you, the requestor. Future requests would simply hit the CDN, see the file present, and serve it to you from the fastest edge node.

Because fingerprinting is included out of the box, we do not need to deal with cache invalidations. When the assets change, the fingerprint will change. When that happens, CloudFront will not have the new file, and it will make a request to the origin server to get it. Eventually, the old, unused files will expire. It just works.

Wrap-Up

In this post, we took a Ruby on Rails application and cached its static assets using Amazon CloudFront and the Ruby on Rails asset pipeline. We also discussed the broad strokes of how CloudFront and Rails work together to make this simple to do.

Have any questions, comments, or problems getting your application to cache static content with Amazon CloudFront? Suggestions for topics you would like to see next? Please let us know in the comments!

Deploying Ruby on Rails Applications to AWS OpsWorks

by Alex Wood | on | in Ruby | | Comments

To begin our series on using Ruby on Rails with Amazon Web Services, we are going to start at the beginning: deploying our application. Today, we will be deploying our application to AWS OpsWorks.

Following along with this post, you should be able to deploy our "Todo Sample App" to AWS using OpsWorks, with your application and database running on different machine instances.

Getting Your Application Ready to Deploy

You can deploy the Todo sample application to OpsWorks directly from its public GitHub repo, using the ‘opsworks’ branch. If you explore the repo, you will notice that we’ve made a few design choices:

  • Our secrets file at config/secrets.yml expects the RAILS_SECRET_TOKEN environment variable to be set on our application servers.
  • We have required the mysql2 gem, to interface with a MySQL database.
  • We have required the unicorn gem, and will use unicorn as our app server.

Creating an OpsWorks Stack

Log in to the AWS Console and navigate to the AWS OpsWorks Console. Click Add Stack and fill out the form like so:

Add Stack Screen

Don’t worry about the "Advanced" settings for now – we won’t need them during this part of the tutorial. Once you’ve filled out the form, just press Create Stack and you’re done.

Creating the Rails App Server Layer

After creating a stack, you’ll find yourself at a page prompting you to create a layer, an instance, and an app. To start, click Add a layer.

We are making a few changes to the default options here. They are:

  • Using Ruby version 2.1.
  • Using "nginx and Unicorn" instead of "Apache2 and Passenger".
  • Using RubyGems version 2.2.1.

Once you’re all done, click Add Layer. You’ll be redirected to the "Layers" screen.

Creating the Database Layer

Next, we’re going to create our database layer. On the layers screen, click + Layer.

Add MySQL Layer

Choose "MySQL" from the drop down box, and leave everything else as-is. Of course, if you’re taking your own screenshots, it is best to avoid sharing your passwords of choice as well!

Click Add Layer and you’re done with this step.

MySQL Layer vs. Amazon RDS Layer

When creating your stack, you can choose to use an OpsWorks-managed EC2 instance running MySQL, called a "MySQL" layer, or you can create a layer that points to an existing Amazon RDS instance.

For this example, we are going to use a MySQL layer. You could substitute an RDS layer if you so chose. In future posts, we may explore this option in depth.

Adding Instances

We’ve made layers for our application servers and database, but we do not yet have application servers or a database. We will next create an instance of each.

Create an App Server Instance

From the "Layers" screen, click Add instance in the "Rails App Server" layer.

Add Rails Instance

We’re creating a t2.micro instance to optimize for cost (this is a demo after all). You may also want to create an SSH key and specify it here in order to be able to log in to your host for debugging purposes, but we don’t strictly need it so we are going to skip that for now.

Click Add Instance once you’re done, then start to begin the instance setup process. While that runs, we are going to make our database instance.

One quick aside about using a t2.micro instance: you can only create them in a VPC. We have created a VPC in this example, but if you were creating a stack without a VPC, t2.micro instances will not be available to you. Other instance types will, of course, work for this example.

Create a Database Instance

You’ll note that, if you’re following along with each step, you’re now at the "Instances" page. From either here or the layers page, under "MySQL", click Add an instance.

Add MySQL Instance

As before, we are creating a t2.micro instance. Click Add Instance to create the instance, and start to begin instance setup.

Adding the Application

While our instances are set up, let’s add our application. Click the Apps link on the sidebar, then click Add an app.

Add App

For this example, we’re using the Git repository at https://github.com/awslabs/todo-sample-app.git as our Application Source, and using the opsworks branch to ensure that you’re deploying the same code I was as this post was written. You can name the app whatever you’d like, but the "TodoApp" name will match with fields we will fill out later, so if you do change the name, make sure to use that new name going forward wherever we use "TodoApp".

Add App

To generate a value for the RAILS_SECRET_KEY environment variable, you can use the command rake secret within your copy of the repo. Just remember to set this as a "Protected value", and if you’re taking screenshots of your process, this is a good time to remove the placeholder value you used for the screenshot and to add a new value generated with rake secret.

Click Add App when you are done.

Deploying the Application

It is likely that your instances are done being created and set up by now, but double check that they are both online before continuing to this step. If by chance they are not quite set up, by the time you prepare a cup of tea and come back, they should be ready.

Click the Deployments link on the sidebar, then click the Deploy an App button.

Deploy App

Since we have not done so yet, remember to check "Yes" for the "Migrate database" setting. We will also need this custom JSON to ensure the "mysql2" adapter is used as intended:

{
  "deploy":
  {
    "todoapp":
    {
      "database":
      {
        "adapter": "mysql2"
      }
    }
  }
}

Click Deploy, and grab another cup of tea. You’ve now deployed the Ruby on Rails "Todo" sample app to AWS OpsWorks!

Use Custom JSON for All Deployments

You probably don’t want to be filling in the custom JSON for your adapter choice with every deployment. Fortunately, you can move this custom JSON into your stack settings to have it go with every deployment.

Click the Stack link on the sidebar, open Stack Settings, and click Edit.

Stack Settings

Add the custom JSON you used for your deployment earlier, and click Save.

Try It Out

To view the app in action, click on your app server’s name on the deployment screen to go to the server’s info page. Click the link next to "Public DNS", and you should see the front page of the application:

You can add tasks, mark them complete, and delete them as you like. In short, your application is running and performing database transactions.

Hello TodoApp!

Wrap-Up

In this post, we started with a Ruby on Rails application, and went step-by-step through the process to get it up and running on AWS with OpsWorks. Now, you can follow this same process to get your own Rails application running on AWS.

Now that we can deploy our application, we will begin to explore ways to make our app scale, improve availability, and optimize some common speed bottlenecks.

Have any questions, comments, or problems getting the app up and running? Suggestions for topics you would like to see next? Please reach out to us in the comments!

Blog Series: Ruby on Rails on Amazon Web Services

by Alex Wood | on | in Ruby | | Comments

Welcome to a series on how to integrate Ruby on Rails apps with Amazon Web Services. In this series, we’re going to start from scratch with a simple app, and show you how to make it scalable, highly available, and fault tolerant.

The Sample App

For this blog series, we have built a sample app in Ruby on Rails. You can find it on GitHub as awslabs/todo-sample-app.

The app itself is designed to be simple to follow. It is a very basic todo list, where you can add tasks, mark them complete, or delete them, all on a single page. In this way, we can focus on the code changes needed to integrate the app with Amazon Web Services, without worrying about confusion over what the app itself does.

There’s no hand-waving here: all the code you need to do this is in this repo, and all the setup you need to do in AWS is in the posts.

What the Series Will Cover

We’re going to start by covering how to deploy the TodoApp to the cloud using AWS OpsWorks. Then, we will talk about speeding up your app by caching your static assets with Amazon CloudFront. We will go on to discuss other scaling and performance improvements you can make to solve real-world problems in the cloud.

Have a topic you’d love for us to cover? Let us know in the comments!

Up Next

The first post, showing you how to deploy the Todo Sample App to AWS OpsWorks will be out soon. Stay tuned!

DynamoDB Session Store for Rack Applications

by Loren Segal | on | in Ruby | | Comments

Today we are announcing a new RubyGem that enables your Ruby on Rails or Rack-based applications to store session data inside of Amazon DynamoDB. The gem acts as a drop-in replacement for session stores inside of Rails and can also run as a Rack middleware for non-Rails apps. You can read more about how to install and configure the gem on the GitHub repository: aws/aws-sessionstore-dynamodb-ruby. If you want to get started right away, just add the gem to your Gemfile via:

gem 'aws-sessionstore-dynamodb', '~> 1.0'

For me, the best part of this gem is that it was the product of a summer internship project by one of our interns, Ruby Robinson. She did a great job ramping up on new skills and technologies, and ultimately managed to produce some super well-tested and idiomatic code in a very short period of time. Here’s Ruby in her own words:

Hello, my name is Ruby Robinson, and I was a summer intern with the AWS Ruby SDK team. My project was to create a RubyGem (aws-sessionstore-dynamodb) that allowed Rack applications to store sessions in Amazon DynamoDB.

I came into the internship knowing Java and, ironically, not knowing Ruby. It was an opportunity to learn something new and contribute to the community. After pouring myself through a series of books, tutorials, and blogs on Ruby, Ruby on Rails, and Rack, the gem emerged; with help from Loren and Trevor.

Along with creating the gem, I got to experience the Amazon engineering culture. It largely involves taking ownership of projects, innovation, and scalability. I got to meet with engineers who were solving problems at scales I had only heard of. With an Amazon internship, you are not told what to do; you are asked what you are going to do. As my technical knowledge grew, I was able to take ownership of my project and drive it to completion.

In the end I produced a gem with some cool features! The gem is a drop-in replacement for the default session store that gives you the persistence and scale of Amazon DynamoDB. So, what are you waiting for? Check out the gem today!

The experience of bringing a developer from another language into Ruby taught me quite a bit about all of the great things that our ecosystem provides us, and also shined a light on some of the things that are more confusing to newbies. In the end, it was extremely rewarding to watch someone become productive in the language in such a short period of time. I would recommend that everyone take the opportunity to teach new Rubyists the language, if that opportunity ever arises. I think it’s also important that we encourage new developers to become active in the community and write more open source code, since that’s what makes our ecosystem so strong. So, if you know of a new Rubyist in your area, invite them out to your local Ruby meetup or hackfest and encourage them to contribute to some of the projects. You never know, in a few years these might be the people writing and maintaining the library code you depend on every day.

And with that said, please check out our new Amazon DynamoDB Session Store for Rack applications and let us know what you think, either here, or on GitHub!