Ruby – AWS Developer Blog https://aws.amazon.com/blogs/developer/ Mon, 04 Dec 2017 19:47:18 +0000 en-US hourly 1 Introducing Support for Generating Ruby SDKs in Amazon API Gateway https://aws.amazon.com/blogs/developer/introducing-support-for-generating-ruby-sdks-in-amazon-api-gateway/ Mon, 20 Nov 2017 19:08:12 +0000 9287055897c7925e899d96f58b71f25fe25fe64d We’re excited to announce support for generating Ruby SDKs from Amazon API Gateway. The Ruby SDKs you generated are compatible with Ruby 1.9 and later. Generated SDKs have first-class support for API keys, custom or AWS Identity and Access Management (IAM) authentication, automatic and configurable retries, exception handling, and all privileges of aws-sdk-core version 3 […] <p>We’re excited to announce support for generating Ruby SDKs from Amazon API Gateway. The Ruby SDKs you generated are compatible with Ruby 1.9 and later. Generated SDKs have first-class support for API keys, custom or <a href="https://aws.amazon.com/iam/" title="undefined" target="null">AWS Identity and Access Management (IAM)</a> authentication, automatic and configurable retries, exception handling, and all privileges of <code>aws-sdk-core</code> <a href="https://rubygems.org/gems/aws-sdk-core" title="gem 3.0" target="_blank">version 3</a> has as well. In this blog post, we’ll walk through how to create an example API and generate a Ruby SDK from that API. We also explore various features of the generated SDK. In this post, we assume you have some familiarity with <a href="http://docs.aws.amazon.com/apigateway/latest/developerguide/welcome.html" title="undefined" target="null">API Gateway</a> concepts.</p> <h2>Creating an example API</h2> <p>To start, let’s create an sample API by using the API Gateway console.<br /> Open the API Gateway console, choose&nbsp;<strong>Create API</strong>, and then choose <strong>Example API</strong>. Then choose <strong>Import</strong>&nbsp;to create the example API.</p> <p><a href="https://d2908q01vomqb2.cloudfront.net/0716d9708d321ffb6a00818614779e779925365c/2017/11/09/ruby_apig_create-1.png"><img src="https://d2908q01vomqb2.cloudfront.net/0716d9708d321ffb6a00818614779e779925365c/2017/11/09/ruby_apig_create-1.png" alt="" width="1667" height="822" class="alignnone size-full wp-image-3207" /></a></p> <p>This simple, example API has four straightforward operations:</p> <ul type="disc"> <li>A GET on the API root resource that returns HTML describing the API</li> <li>A GET on the /pets resource that returns a list of Pets</li> <li>A POST on the /pets resource that creates a new Pet</li> <li>A GET on the /pets/{petId} resource that returns a specific Pet by ID</li> </ul> <p>You can find more information about this example in the <a href="http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-from-example.html" title="undefined" target="null">API Gateway documentation</a>.</p> <h2>Deploying the API</h2> <p>Next, let’s deploy our API to a stage.<br /> From <strong>Actions</strong> choose <strong>Deploy API</strong>.</p> <p><a href="https://d2908q01vomqb2.cloudfront.net/0716d9708d321ffb6a00818614779e779925365c/2017/11/09/deploy-1.png"><img src="https://d2908q01vomqb2.cloudfront.net/0716d9708d321ffb6a00818614779e779925365c/2017/11/09/deploy-1.png" alt="" width="868" height="568" class="alignnone size-full wp-image-3208" /></a></p> <p>On the stage deployment page, name the stage <strong>Test</strong>, and then choose <strong>Deploy</strong>.<br /> <a href="https://d2908q01vomqb2.cloudfront.net/0716d9708d321ffb6a00818614779e779925365c/2017/11/09/stage.png"><img src="https://d2908q01vomqb2.cloudfront.net/0716d9708d321ffb6a00818614779e779925365c/2017/11/09/stage.png" alt="" width="594" height="395" class="alignnone size-full wp-image-3210" /></a></p> <p>After deploying, the&nbsp;<strong>SDK Generation</strong>&nbsp;tab is available. For <strong>Platform</strong>, choose&nbsp;<strong>Ruby</strong>.&nbsp;<br /> For <strong>Service Name</strong>, type <strong>Pet</strong>.</p> <p>Choose <strong>Generate SDK</strong>, and then extract the downloaded SDK package.</p> <p><a href="https://d2908q01vomqb2.cloudfront.net/0716d9708d321ffb6a00818614779e779925365c/2017/11/09/ruby-1.png"><img src="https://d2908q01vomqb2.cloudfront.net/0716d9708d321ffb6a00818614779e779925365c/2017/11/09/ruby-1.png" alt="" width="1706" height="592" class="alignnone size-full wp-image-3209" /></a></p> <p>The following are the configuration options available for the Ruby platform:</p> <ul type="disc"> <li><strong>Service Name</strong> – Used to generate the Ruby gem namespace for your APIs.</li> <li><strong>Ruby Gem Name</strong> – The name of the Ruby gem your generated SDK code will be placed under. If you don’t provide a name, this defaults to the service name in lowercase, with the “sdk” suffix.</li> <li><strong>Ruby Gem Version</strong> – The version number for the generated Ruby gem. If you don’t provide a version number, this defaults to 1.0.0 if not provided.</li> </ul> <p>These are basic Ruby gem configuration options. You can customize your Ruby gemspec in the generated SDK gem later.</p> <h2>Using the generated Ruby SDK gem</h2> <p>Navigate to the location of your downloaded SDK gem. The directory structure looks like the following.</p> <p><a href="https://d2908q01vomqb2.cloudfront.net/0716d9708d321ffb6a00818614779e779925365c/2017/11/09/struct.png"><img src="https://d2908q01vomqb2.cloudfront.net/0716d9708d321ffb6a00818614779e779925365c/2017/11/09/struct.png" alt="" width="683" height="362" class="alignnone size-full wp-image-3200" /></a></p> <p><strong>Note</strong><br /> <code>/features</code> and <code>/spec</code> directories are currently left empty for integration and unit tests that you can add to the SDK. The generated SDK is fully documented for operations and shapes in the source code.</p> <h2>Exploring the SDK</h2> <p>Let’s explore the SDK by building a Ruby gem from the generated source, as follows.</p> <pre><code class="lang-bash"># change to /pet-sdk directory cd pet-sdk # build the generated gem gem build pet-sdk.gemspec # then you can see pet-sdk-1.0.0.gem is available </code></pre> <p>Then, install the gem, as follows.</p> <pre><code class="lang-bash">gem install pet-sdk-1.0.0.gem </code></pre> <p>Finally, create the client.</p> <pre><code class="lang-ruby">require 'pet-sdk' client = Pet::Client.new </code></pre> <h3>Features in the client</h3> <p>Now you have your own client that includes multiple features from the official <a href="https://github.com/aws/aws-sdk-ruby" title="undefined" target="null">AWS SDK for Ruby</a>. These include default exponential backoff retries, HTTP wire logging options, configurable timeouts, and more.</p> <p>For example:</p> <pre><code class="lang-ruby">require 'pet-sdk' client = Pet::Client.new( http_wire_trace: true, retry_limit: 5, http_read_timeout: 50 ) </code></pre> <h3>Making API calls</h3> <p>Let’s see all the API methods that are available and use your SDK’s built-in parameter validators to make a successful API call:</p> <pre><code class="lang-ruby">client.operation_names # =&gt; [:create_pet, :get_api_root, :get_pet, :get_pets] # get me all my pets resp = client.get_pets </code></pre> <p>You should see a response like the following.<br /> <a href="https://d2908q01vomqb2.cloudfront.net/0716d9708d321ffb6a00818614779e779925365c/2017/11/10/Screen-Shot-2017-11-09-at-4.29.12-PM.png"><img src="https://d2908q01vomqb2.cloudfront.net/0716d9708d321ffb6a00818614779e779925365c/2017/11/10/Screen-Shot-2017-11-09-at-4.29.12-PM.png" alt="" width="569" height="135" class="alignnone size-full wp-image-3219" /></a></p> <pre><code class="lang-ruby"># I want the cat client.get_pet # ArgumentError: missing required parameter params[:pet_id] # providing :pet_id client.get_pet(pet_id: 2) # ArgumentError: expected params[:pet_id] to be a String, got value 2 (class: Fixnum) instead. # fix the value type resp = client.get_pet(pet_id: &quot;2&quot;) </code></pre> <p>Now you can see a correct response like the following.<br /> <a href="https://d2908q01vomqb2.cloudfront.net/0716d9708d321ffb6a00818614779e779925365c/2017/11/10/Screen-Shot-2017-11-09-at-4.29.22-PM.png"><img src="https://d2908q01vomqb2.cloudfront.net/0716d9708d321ffb6a00818614779e779925365c/2017/11/10/Screen-Shot-2017-11-09-at-4.29.22-PM.png" alt="" width="921" height="46" class="alignnone size-full wp-image-3220" /></a>If you have some familiarity with the AWS SDK for Ruby, you should find the experience similar to using an AWS service client.</p> <h2>Generate a Ruby SDK from an API</h2> <p>In addition to using the API Gateway console to generate a Ruby SDK, the <code>get_sdk</code> API is <a href="http://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/APIGateway/Client.html#get_sdk-instance_method" title="undefined" target="null">available</a> in all of the AWS SDKs and tools, including the AWS SDK for Ruby.</p> <p>For this example, we assume that you have some familiarity with the AWS SDK for Ruby. You can find a quick introduction to the SDK for Ruby <a href="https://github.com/aws/aws-sdk-ruby/blob/master/README.md" title="undefined" target="null">here</a>.</p> <pre><code class="lang-ruby">require 'aws-sdk-apigateway' client = Aws::ApiGateway::Client.new(region: 'us-west-2') resp = client.get_sdk({ rest_api_id: MY_REST_API_ID, # required stage_name: DEPLOY_STAGE_NAME, # required sdk_type: &quot;ruby&quot;, # required parameters: { &quot;service.name&quot; =&gt; &quot;PetStore&quot;, # required &quot;ruby.gem-name&quot; =&gt; &quot;pet&quot;, &quot;ruby.gem-version&quot; =&gt; &quot;0.0.1&quot; }, }) </code></pre> <h2>Final thoughts</h2> <p>This post highlights how to generate a Ruby client SDK for an API in API Gateway, and how to call the API using the generated SDK in an application. For more information about using a generated SDK, see your&nbsp;<code>README.md</code>&nbsp;file in the uncompressed generated SDK gem folder. Details of example usage of your API are also generated in source file documentation blocks.</p> <h2>Feedback</h2> <p>Please share your questions, comments, and issues with us on <a href="https://github.com/aws/aws-sdk-ruby" title="Github" target="null">GitHub</a>. Feel free to open a support ticket with <a href="https://console.aws.amazon.com/support/home" title="AWS Support" target="null">AWS Support</a> if you find an issue with your API model. You can also catch us in our <a href="https://gitter.im/aws/aws-sdk-ruby" title="Gitter" target="null">Gitter</a> channel.</p> Announcing the Modularized AWS SDK for Ruby (Version 3) https://aws.amazon.com/blogs/developer/announcing-the-modularized-aws-sdk-for-ruby-version-3/ Tue, 29 Aug 2017 18:27:06 +0000 03d879184e25a29e49078a6638cbc10cc3b83bc4 We’re excited to announce today’s stable release of version 3 of the&nbsp;AWS SDK for Ruby. The SDK is now available with over 100 service-specific gems (starting with&nbsp;aws-sdk-*, such as&nbsp;aws-sdk-s3) on&nbsp;RubyGems. You can find a full list of available service gems can be found at our GitHub&nbsp;landing page. Features Version 3 of the AWS SDK for […] <p>We’re excited to announce today’s stable release of version 3 of the&nbsp;<a title="AWS SDK for Ruby" href="https://aws.amazon.com/sdk-for-ruby/" target="null">AWS SDK for Ruby</a>. The SDK is now available with over 100 service-specific gems (starting with&nbsp;<code>aws-sdk-*</code>, such as&nbsp;<code>aws-sdk-s3</code>) on&nbsp;<a title="RubyGems aws-sdk" href="https://rubygems.org/gems/aws-sdk" target="null">RubyGems</a>. You can find a full list of available service gems can be found at our <a title="aws-sdk-ruby on GitHub" href="https://github.com/aws/aws-sdk-ruby#supported-services" target="null">GitHub&nbsp;landing page</a>.</p> <h2>Features</h2> <p>Version 3 of the AWS SDK for Ruby modularizes the monolithic SDK into service-specific gems, for example,&nbsp;<code>aws-sdk-s3</code>&nbsp;and&nbsp;<code>aws-sdk-dynamodb</code>. Now each service gem uses strict&nbsp;<a title="Semantic Versioning" href="http://semver.org/" target="null">semantic versioning</a>, along with the benefits of continuous delivery of AWS API updates. With modularization, you can pick and choose which service gems your application or library requires, and update service gems independently of each other.</p> <p>These new service-specific gems use statically generated code, rather than runtime-generated clients and types. This provides human-readable stack traces and code for API clients. Additionally, version 3 eliminates many thread safety issues by removing Ruby&nbsp;<code>autoload</code>&nbsp;statements. When you require a service gem, such as&nbsp;<code>aws-sdk-ec2</code>, all of the code is loaded upfront, avoiding sync issues with&nbsp;<code>autoload</code>.</p> <p>Furthermore, the SDK provides&nbsp;<a title="AWS Signature Version 4" href="http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html" target="null">AWS Signature Version 4</a>&nbsp;signing functionality as a separate gem&nbsp;<code>aws-sigv4</code>. This gem provides flexible signing usage for both AWS requests and customized scenarios.</p> <h2>Upgrading</h2> <p>We’ve provided a detailed&nbsp;<a title="V3 Upgrading Guide" href="https://github.com/aws/aws-sdk-ruby/blob/master/V3_UPGRADING_GUIDE.md" target="null">upgrading guide</a>&nbsp;with this release, which covers different upgrade scenarios. In short, the public-facing APIs are compatible, and so changes you need to make are focused on your&nbsp;<code>Gemfile</code>&nbsp;and&nbsp;<code>require</code> statements.</p> <p>Most users of the SDK have a setup similar to this:</p> <pre><code class="lang-ruby"># Gemfile gem 'aws-sdk', '~&gt; 2'</code></pre> <pre><code class="lang-ruby"># Code Files require 'aws-sdk' s3 = Aws::S3::Client.new ddb = Aws::DynamoDB::Client.new # etc.</code></pre> <p>If that’s you, the quickest migration path is to simply change your&nbsp;<code>Gemfile</code>&nbsp;like so:</p> <pre><code class="lang-ruby"># Gemfile gem 'aws-sdk', '~&gt; 3'</code></pre> <p>However, this will pull in many new dependencies, as each service client has its own individual gem. As a direct user, you can also change to using only the service gems actually required by your project, which is the recommended path. This would involve a change to both your&nbsp;<code>Gemfile</code>&nbsp;and to the code files where your&nbsp;<code>require</code>&nbsp;statements live, like so:</p> <pre><code class="lang-ruby"># Gemfile gem 'aws-sdk-s3', '~&gt; 1' gem 'aws-sdk-dynamodb', '~&gt; 1'</code></pre> <pre><code class="lang-ruby"># Code Files require 'aws-sdk-s3' require 'aws-sdk-dynamodb' s3 = Aws::S3::Client.new ddb = Aws::DynamoDB::Client.new # etc.</code></pre> <p>Other upgrade cases are covered in the&nbsp;guide.</p> <h2>Feedback</h2> <p>Please share your questions, comments, issues, etc. with us on&nbsp;<a title="GitHub Page: AWS SDK for Ruby" href="https://github.com/aws/aws-sdk-ruby" target="null">GitHub</a>. You can also catch us in our&nbsp;<a title="Gitter" href="https://gitter.im/aws/aws-sdk-ruby" target="null">Gitter</a> channel.</p> Upgrading from Version 2 to Version 3 of the AWS SDK for Ruby https://aws.amazon.com/blogs/developer/upgrading-from-version-2-to-version-3-of-the-aws-sdk-for-ruby-2/ Fri, 09 Dec 2016 20:31:18 +0000 a3ca0231b1ba6afa6ba208b0926acc1d5c0417e6 Recently we announced the modularization of the AWS SDK for Ruby. This blog post will focus on how to upgrade your application to use the new service specific gems. This blog post is divided up into sections based on how you currently depend on the AWS SDK for Ruby today. Find the section below that […] <p>Recently we announced the <a href="https://aws.amazon.com/blogs/developer/aws-sdk-for-ruby-modularization-version-3-2/">modularization of the AWS SDK for Ruby</a>. This blog post will focus on how to upgrade your application to use the new service specific gems.</p> <p>This blog post is divided up into sections based on how you currently depend on the AWS SDK for Ruby today. Find the section below that describes how you load the SDK today, and it will guide you in upgrading. <strong>Since version 3 is backwards compatible with version 2, you should not need to make additional changes beyond those described below.</strong></p> <h2 id="toc_1">Bunder: gem ‘aws-sdk’, ‘~&gt;2’</h2> <p>Congratulations! You are following recommended best practices for how to depend on the SDK today. The simplest path to upgrade is to change the version from 2 to 3.</p> <div> <pre><code class="lang-ruby">#gem 'aws-sdk', '~&gt; 2' gem 'aws-sdk', '~&gt; 3'</code></pre> </div> <p>See the section about using service specific gems below.</p> <h2>Bundler: gem ‘aws-sdk’ (without version)</h2> <p>It is not recommended to depend on the SDK without a major version constraint. Fortunately, version 3 is backwards compatible with version 2. Bundle updating your dependencies will work, but consider yourself lucky! You should add the version constraint to protect from future major version changes:</p> <div> <pre><code class="lang-ruby">#gem 'aws-sdk' gem 'aws-sdk', '~&gt; 3'</code></pre> </div> <p>See the section about using service specific gems below.</p> <h2 id="toc_3">Bundler: gem ‘aws-sdk-core’, ‘~&gt; 2’</h2> <p>The <tt>aws-sdk-core</tt> gem changes signification from version 2 to 3. In version 3, the core gem no longer defines any services. It will only contain shared utilities, such as credential providers, serializers, etc. <strong>To upgrade you must make two changes:</strong></p> <ul> <li>Change your bundler dependency</li> <li>Change your ruby require statements</li> </ul> <p>In bundler, replace <tt>aws-sdk-core</tt>, with <tt>aws-sdk</tt>:</p> <div> <pre><code class="lang-ruby">#gem 'aws-sdk-core', '~&gt; 2' gem 'aws-sdk', '~&gt; 3'</code></pre> </div> <p>In code, replace any require statements on <tt>aws-sdk-core</tt> with <tt>aws-sdk</tt>.</p> <div> <pre><code class="lang-ruby">#require 'aws-sdk-core' require 'aws-sdk'</code></pre> </div> <p>See the section about using service specific gems below.</p> <h2>Bundler: gem ‘aws-sdk-core’ (without version)</h2> <p>If you happen to bundle update before changing your Gemfile, your application will be broken. Version 3 of the <tt>aws-sdk-core</tt> gem no longer defines service modules and clients. It is a shared dependency of the 75+ service gems. <strong>To upgrade you must make two changes:</strong></p> <ul> <li>Change your bundler dependency</li> <li>Change your ruby require statements</li> </ul> <p>In bundler, replace <tt>aws-sdk-core</tt>, with <tt>aws-sdk</tt>:</p> <div> <pre><code class="lang-ruby">#gem 'aws-sdk-core' gem 'aws-sdk', '~&gt; 3'</code></pre> </div> <p>In code, replace any require statements on <tt>aws-sdk-core</tt> with <tt>aws-sdk</tt>.</p> <div> <pre><code class="lang-ruby">#require 'aws-sdk-core' require 'aws-sdk'</code></pre> </div> <p>See the section about using service specific gems below.</p> <h2>Bundler: gem ‘aws-sdk-resource’ (with or without version)</h2> <p>In version 3, the <tt>aws-sdk-resources</tt> gem has been removed. This gem will not receive any further updates. Each service gem contains both the client interface, and the resource interfaces. <strong>To upgrade you must make two changes:</strong></p> <ul> <li>Change your bundler dependency</li> <li>Change your ruby require statements</li> </ul> <div> <pre><code class="lang-ruby">#gem 'aws-sdk-resources', '~&gt; 2' gem 'aws-sdk', '~&gt; 3'</code></pre> </div> <p>In code, replace any require statements on <tt>aws-sdk-resources</tt> with <tt>aws-sdk</tt>.</p> <div> <pre><code class="lang-ruby">#require 'aws-sdk-core' require 'aws-sdk'</code></pre> </div> <p>See the section about using service specific gems below.</p> <h2>Using the Service Specific Gems</h2> <p>Each of the instructions above suggested using version 3 of the <tt>aws-sdk</tt> gem. This will work and is the shortest path to upgrading. It will however install 75+ service specific gems. You may choose to replace your dependency on the <tt>aws-sdk</tt> gem with service specific gems.</p> <p>If my application depends on Amazon DynamoDB and Amazon S3, I could make the following changes:</p> <p>In my Gemfile:</p> <div> <pre><code class="lang-ruby">#gem 'aws-sdk', '~&gt; 3' gem 'aws-sdk-dynamodb', '~&gt; 1' gem 'aws-sdk-s3', '~&gt; 1'</code></pre> </div> <p>In my code:</p> <div> <pre><code class="lang-ruby">#require 'aws-sdk' require 'aws-sdk-s3' require 'aws-sdk-dynamodb'</code></pre> </div> <p><strong>If you are a library maintainer, and you depend on the AWS SDK for Ruby, you should use service specific gems.</strong> Do no force your users to install every AWS service gem if you only depend on one.</p> <h2>Conclusion</h2> <p>Upgrading should be very simple. If you encounter any backwards incompatible changes, please open a <a href="https://github.com/aws/aws-sdk-ruby/issues">GitHub issue</a>. The modularized SDK will be in preview for a short period to hopefully catch these issues before going GA. You can also catch us in the <a href="https://gitter.im/aws/aws-sdk-ruby">gitter channel</a>.</p> AWS SDK for Ruby Modularization (Version 3) https://aws.amazon.com/blogs/developer/aws-sdk-for-ruby-modularization-version-3-2/ Fri, 09 Dec 2016 20:31:13 +0000 e190ae679fdb2ab7e4241b768d7a99d73bfed78e Version 3 of the AWS SDK for Ruby is available now as a preview release. This version modularizes the monolithic SDK into service specific gems. Aside from gem packaging differences, version 3 interfaces are backwards compatible with version 2. You can install individual gems like so: $ gem install aws-sdk-s3 --version 1.0.0.rc1 You can install […] <p>Version 3 of the <a href="https://github.com/aws/aws-sdk-ruby">AWS SDK for Ruby</a> is available now as a preview release. This version modularizes the monolithic SDK into service specific gems. Aside from gem packaging differences, version 3 interfaces are backwards compatible with version 2.</p> <p>You can install individual gems like so:</p> <pre>$ gem install aws-sdk-s3 --version 1.0.0.rc1</pre> <p>You can install everything using the <tt>aws-sdk</tt> gem:</p> <pre>$ gem install aws-sdk --version 3.0.0.rc1</pre> <p>To see a complete list of gems, checkout the project README for a list of <a href="https://github.com/aws/aws-sdk-ruby/tree/code-generation#supported-services" target="_blank">supported services and gems</a>.</p> <h2>Motivation</h2> <p>Modularization allows us to make some long requested changes to the SDK. Some of these changes were not reasonable when we shipped a single monolithic gem with 75+ services. Some of the primary motivating factors for breaking up the monolith include:</p> <ul> <li>To provide better versioning information. When 75+ services share a single gem, it is difficult to communicate when a change is meaningful to a user. We can now use strict <a href="http://semver.org/">semantic versioning</a> for each gem.</li> <li>To improve our ability to deliver AWS API updates continuously. The number of new services and updates has been significantly increasing the frequency with which we update. We want to avoid situations where one update is blocked by an unrelated service. We can now continuously deliver updates per service gem.</li> <li>Remove the usage of Ruby `autoload` statements. When you require a service gem, such as aws-sdk-ec2, all of the code is loaded and ready to use. This should eliminate a large number of thread safety issues that users encounter due to the use of <tt>autoload</tt>.</li> <li>A large amount of the dynamic runtime has been replaced with code generation. This allows users to reason better about what code is doing, receive better stack traces, improve performance, etc.</li> </ul> <h2>What Has Changed?</h2> <p>Our intent for the modularization is to keep SDK interfaces backwards compatible. <b>You may need to modify your gem dependency on the AWS SDK for Ruby.</b> The <tt>aws-sdk</tt> and <tt>aws-sdk-core</tt> gems have been bumped to version 3.0 to protect users from package level changes.</p> <p>* Every service has a gem, such as <tt>aws-sdk-s3</tt>.<br /> * The <tt>aws-sdk-core</tt> gem now only contains shared utilities.<br /> * The <tt>aws-sdk-resources</tt> is obsolete. Service gems contain both client and resource interfaces.<br /> * The <tt>aws-sdk</tt> gem now has a dependency on 75+ service gems.</p> <p>Here is a diagram showing the dependencies of the <tt>aws-sdk</tt> gem across its major versions.</p> <p><a href="https://d2908q01vomqb2.cloudfront.net/0716d9708d321ffb6a00818614779e779925365c/2016/12/05/gem-diagram.png" rel="attachment wp-att-1584"><img class="alignnone wp-image-1584 size-full" src="https://d2908q01vomqb2.cloudfront.net/0716d9708d321ffb6a00818614779e779925365c/2016/12/05/gem-diagram.png" alt="gem-diagram" width="644" height="282" /></a></p> <h2>Why Bump to Version 3?</h2> <p>The version 2 <tt>aws-sdk-core</tt> gem includes code that defines 75+ service modules and shared utilities. It is important to prevent a service specific gem, such as <tt>aws-sdk-s3</tt> and the core gem from both defining the same interfaces.</p> <p>While we have worked hard to ensure full backwards compatibility in the service interfaces, a small number of private internal interfaces have been removed or changed. For users that have relied on these un-documented interfaces, this will prevent unexpected breaks with a gem update. Some of these changes include:</p> <ul> <li>Removed the internal runtime methods <tt>Aws.add_service</tt> and <tt>Aws.service_added</tt>. These methods were used by the runtime to detect when a service was autoloaded.</li> <li>Removed the internal <tt>Aws::Signers</tt> module and the various signature classes therein. These classes were marked with <tt>@api private</tt>. They are now available as separate gems: <ul> <li><tt>aws-sigv4</tt></li> <li><tt>aws-sigv2</tt></li> </ul> </li> </ul> <h2>Migrating Code From Version 2 to Version 3</h2> <p>Migrating should be very simple. <b>If you depend on <tt>aws-sdk</tt>, then you do not need to change anything.</b> If you depend on <tt>aws-sdk-resources</tt> or <tt>aws-sdk-core</tt>, replace these with a dependency on one of the following:</p> <p>* <tt>aws-sdk ~&gt; 3.0</tt><br /> * Service specific gems, such as <tt>aws-sdk-s3 ~&gt; 1.0</tt></p> <p>You will also need to replace your require statements. You should no longer call <tt>require &quot;aws-sdk-resources&quot;</tt> or <tt>require &quot;aws-sdk-core&quot;</tt>. A <a href="https://aws.amazon.com/blogs/developer/aws-sdk-for-ruby-modularization-version-3/">follow-up blog post</a> provides detailed instructions on upgrading.</p> <h2>Questions?</h2> <p>Join us in our <a href="https://gitter.im/aws/aws-sdk-ruby">Gitter channel</a> with your questions and feedback. The modularized released is currently published as a preview gem (rc1). We would love for you to try things out and to share feedback for these are GA.</p> General Availability Release of the aws-record Gem https://aws.amazon.com/blogs/developer/general-availability-release-of-the-aws-record-gem/ Mon, 15 Aug 2016 20:02:45 +0000 2d31c06e5e3802fcf04c3bc1c656a0da8525b4f1 Today, we’re pleased to announce the GA release of version 1.0.0 of the aws-record gem. What Is aws-record? In version 1 of the AWS SDK for Ruby, the AWS::Record class provided a data mapping abstraction over Amazon DynamoDB operations. Earlier this year, we released the aws-record developer preview as a separately packaged library to provide […] <p>Today, we’re pleased to announce the GA release of version <code>1.0.0</code> of the <code>aws-record</code> gem.</p> <h2>What Is aws-record?</h2> <p>In version 1 of the AWS SDK for Ruby, the <code>AWS::Record</code> class provided a data mapping abstraction over <a href="https://aws.amazon.com/dynamodb/">Amazon DynamoDB</a> operations. Earlier this year, we released the <code>aws-record</code> developer preview as a separately packaged library to provide a similar data mapping abstraction for DynamoDB, built on top of the AWS SDK for Ruby version 2. After customer feedback and some more development work, we’re pleased to move the library out of developer preview to general availability.</p> <h2>How to Include the aws-record Gem in Your Project</h2> <p>The <code>aws-record</code> gem is available now from RubyGems:</p> <p>&nbsp;</p> <pre class="brush: bash">gem install aws-record </pre> <p>&nbsp;</p> <p>You can also include it in your project’s Gemfile:</p> <p>&nbsp;</p> <pre class="brush: ruby"># Gemfile gem 'aws-record', '~&gt; 1.0' </pre> <p>&nbsp;</p> <p>This automatically includes a dependency on the <code>aws-sdk-resources</code> gem, major version 2. Be sure to include the <code>aws-sdk</code> or <code>aws-sdk-resources</code> gem in your Gemfile if you need to lock to a specific version, like so:</p> <p>&nbsp;</p> <pre class="brush: ruby"> # Gemfile gem 'aws-record', '~&gt; 1.0' gem 'aws-sdk-resources', '~&gt; 2.5' </pre> <p>&nbsp;</p> <h2>Working with DynamoDB Tables Using the aws-record Gem</h2> <h3>Defining an Aws::Record Model</h3> <p>The <code>aws-record</code> gem provides the <code>Aws::Record</code> module, which you can include in a class definition. This decorates your class with a variety of helper methods that can simplify interactions with Amazon DynamoDB. For example, the following model uses a variety of preset attribute definition helper methods and attribute options:</p> <p>&nbsp;</p> <pre class="brush: ruby">require 'aws-record' class Forum include Aws::Record string_attr :forum_uuid, hash_key: true integer_attr :post_id, range_key: true string_attr :author_username string_attr :post_title string_attr :post_body string_set_attr :tags, default_value: Set.new datetime_attr :created_at, database_attribute_name: &quot;PostCreatedAtTime&quot; boolean_attr :moderation, default_value: false end </pre> <p>&nbsp;</p> <h4>Using Validation Libraries with an Aws::Record Model</h4> <p>The <code>aws-record</code> gem does not come with a built-in validation process. Rather, it is designed to be a persistence layer, and to allow you to bring your own validation library. For example, the following model includes the popular <code>ActiveModel::Validations</code> module, and has defined a set of validations that will be run when we attempt to save an item:</p> <p>&nbsp;</p> <pre class="brush: ruby">require 'aws-record' require 'active_model' class Forum include Aws::Record include ActiveModel::Validations string_attr :forum_uuid, hash_key: true integer_attr :post_id, range_key: true string_attr :author_username string_attr :post_title string_attr :post_body string_set_attr :tags, default_value: Set.new datetime_attr :created_at, database_attribute_name: &quot;PostCreatedAtTime&quot; boolean_attr :moderation, default_value: false validates_presence_of :forum_uuid, :post_id, :author_username validates_length_of :post_title, within: 4..30 validates_length_of :post_body, within: 2..5000 end </pre> <p>&nbsp;</p> <h3>Creating a DynamoDB Table for a Model with Aws::Record::TableMigration</h3> <p>The <code>aws-record</code> gem provides a helper class for table operations, such as migrations. If we wanted to create a table for our <code>Forum</code> model in DynamoDB, we would run the following migration:</p> <p>&nbsp;</p> <pre class="brush: ruby">migration = Aws::Record::TableMigration.new(Forum) migration.create!( provisioned_throughput: { read_capacity_units: 5, write_capacity_units: 2 } ) migration.wait_until_available </pre> <p>&nbsp;</p> <p>You can write these migrations in your <code>Rakefile</code> or as standalone helper scripts for your application. Because you don’t need to update your table definition for additions of non-key attributes, you may find that you’re not running migrations as often for your <code>Aws::Record</code> models.</p> <h2>Working with DynamoDB Items Using the aws-record Gem</h2> <h3>Creating and Persisting a New Item</h3> <p>Using the example model above, once it has been created in the DynamoDB remote end using <code>Aws::Record::TableMigration</code> (or if it already existed in the remote end), it is simple to create and save a new item:</p> <p>&nbsp;</p> <pre class="brush: ruby">post = Forum.new( forum_uuid: FORUM_UUID, post_id: 1, author_username: &quot;Author One&quot;, post_title: &quot;Hello!&quot;, post_body: &quot;Hello, world!&quot; ) post.created_at = Time.now post.save # Performs a put_item call. </pre> <p>&nbsp;</p> <p>You can set attributes when you initialize a new item and with setter methods that are defined for you automatically.</p> <h3>Finding and Modifying an Item</h3> <p>A class-level method <code>#find</code> is provided to look up items from DynamoDB using your model’s key attributes. After setting a few new attribute values, calling <code>#save</code> will make an update call to DynamoDB, reflecting only the item changes you’ve made. This is important for users who are fetching items with projections (which may not include all attributes), or using single-table inheritance patterns (who may not have modeled all attributes present in a remote item), to avoid clobbering unmodeled or non-included attribute values.</p> <p>&nbsp;</p> <pre class="brush: ruby">post = Forum.find(forum_uuid: FORUM_UUID, post_id: 1) post.post_title = &quot;(Removed)&quot; post.post_body = &quot;(Removed)&quot; post.moderation = true post.save # Performs an update_item call on dirty attributes only. </pre> <p>&nbsp;</p> <p>There is also a class-level method to directly build and make an update call to DynamoDB, using key attributes to identify the item and non-key attributes to form the update expression:</p> <p>&nbsp;</p> <pre class="brush: ruby">Forum.update( forum_uuid: FORUM_UUID, post_id: 1, post_title: &quot;(Removed)&quot;, post_body: &quot;(Removed)&quot;, moderation: true ) </pre> <p>&nbsp;</p> <p>The preceding two code examples are functionally equivalent. You’ll have the same database state after running either snippet.</p> <h4>A Note on Dirty Tracking</h4> <p>In our last example, we talked about how item updates only reflect changes to modified attributes. Users of <code>ActiveRecord</code> or similar libraries will be familiar with the concept of tracking dirty attribute values, but <code>aws-record</code> is a bit different. That is because DynamoDB supports collection attribute types, and in Ruby, collection types are often modified through object mutation. To properly track changes to an item when objects can be changed through mutable state, <code>Aws::Record</code> items will, by default, keep deep copies of your attribute values when loading from DynamoDB. Attribute changes through mutation, like this example, will work the way you expect:</p> <p>&nbsp;</p> <pre class="brush: ruby">post = Forum.find(forum_uuid: FORUM_UUID, post_id: 1) post.tags.add(&quot;First&quot;) post.dirty? # =&gt; true post.save # Will call update_item with the new tags collection. </pre> <p>&nbsp;</p> <p>Tracking deep copies of attribute values has implications for performance and memory. You can turn off mutation tracking at the model level. If you do so, dirty tracking will still work for new object references, but will not work for mutated objects:</p> <p>&nbsp;</p> <pre class="brush: ruby">class NoMTModel include Aws::Record disable_mutation_tracking string_attr :key, hash_key: true string_attr :body map_attr :map end item = NoMTModel.new(key: &quot;key&quot;, body: &quot;body&quot;, map: {}) item.save # Will call put_item item.map[:key] = &quot;value&quot; item.dirty? # =&gt; false, because we won't track mutations to objects item.body = &quot;New Body&quot; item.dirty? # =&gt; true, because we will still notice reassignment # Will call update_item, but only update :body unless we mark map as dirty explicitly. item.save </pre> <p>&nbsp;</p> <h2>Try the aws-record Gem Today!</h2> <p>We’re excited to hear about what you’re building with <code>aws-record</code>. Feel free to leave your feedback in the comments, or open an issue in our <a href="https://github.com/aws/aws-sdk-ruby-record">GitHub</a> repo. Read through the <a href="http://docs.aws.amazon.com/awssdkrubyrecord/api/index.html">documentation</a> and get started!</p> Introducing the Aws::Record Developer Preview https://aws.amazon.com/blogs/developer/introducing-the-awsrecord-developer-preview/ Wed, 02 Mar 2016 17:11:37 +0000 354476ef72a6ffd05a7b78fe9649c1a6af9f00ed We are happy to announce that the aws-record gem is now in Developer Preview and available for you to try. What Is Aws::Record? In version 1 of the AWS SDK for Ruby, the AWS::Record class provided a data mapping abstraction over Amazon DynamoDB operations. As version 2 of the AWS SDK for Ruby was being […] <p> We are happy to announce that the <code>aws-record</code> gem is now in Developer Preview and available for you to try.</p> <h2> What Is Aws::Record?</h2> <p> In version 1 of the AWS SDK for Ruby, the <code>AWS::Record</code> class provided a data mapping abstraction over Amazon DynamoDB operations. As version 2 of the AWS SDK for Ruby was being developed, many of you asked for an updated version of the library.</p> <p> The <code>aws-record</code> gem provides a data mapping abstraction for DynamoDB built on top of the AWS SDK for Ruby version 2.</p> <h2> Using Aws::Record</h2> <p> You can download the <code>aws-record</code> gem from RubyGems by including the <code>--pre</code> flag in a gem installation:</p> <pre class="brush: bash"> gem install 'aws-record' --pre </pre> <p> You can also include it in your Gemfile. Do not include a version lock yet, so that <code>bundler</code> can find the pre-release version:</p> <pre class="brush: ruby"> # Gemfile gem 'aws-record' </pre> <h3> Defining a Model</h3> <p> To create an aws-record model, include the <code>Aws::Record</code> module in your class definition:</p> <pre class="brush: ruby"> require 'aws-record' class Forum include Aws::Record end </pre> <p> This will decorate your class with helper methods you can use to create a model compatible with DynamoDB’s table schemas. You might define keys for your table:</p> <pre class="brush: ruby"> require 'aws-record' class Forum include Aws::Record string_attr :forum_uuid, hash_key: true integer_attr :post_id, range_key: true end </pre> <p> When you use these helper methods, you do not need to worry about how to define these attributes and types in DynamoDB. The helper methods and marshaler classes are able to define your table and item operations for you. The <code>aws-record</code> gem comes with predefined attribute types that cover a variety of potential use cases:</p> <pre class="brush: ruby"> require 'aws-record' class Forum include Aws::Record string_attr :forum_uuid, hash_key: true integer_attr :post_id, range_key: true string_attr :author_username string_attr :post_title string_attr :post_body datetime_attr :created_at map_attr :post_metadata end </pre> <h3> Creating a DynamoDB Table</h3> <p> The <code>aws-record</code> gem provides a helper class for table operations, such as migrations. If we wanted to create a table for our <code>Forum</code> model in DynamoDB, we would run the following migration:</p> <pre class="brush: ruby"> require 'forum' # Depending on where you defined the class above. migration = Aws::Record::TableMigration.new(Forum) migration.create!( provisioned_throughput: { read_capacity_units: 10, write_capacity_units: 4 } ) migration.wait_until_available # Blocks until table creation is complete. </pre> <h3> Operations with DynamoDB Items</h3> <p> With a model and table defined, we can perform operations that relate to items in our table. Let’s create a post:</p> <pre class="brush: ruby"> require 'forum' require 'securerandom' uuid = SecureRandom.uuid post = Forum.new post.forum_uuid = uuid post.post_id = 1 post.author_username = &quot;User1&quot; post.post_title = &quot;Hello!&quot; post.post_body = &quot;Hello Aws::Record&quot; post.created_at = Time.now post.post_metadata = { this_is_a: &quot;Post&quot;, types_supported_include: [&quot;String&quot;, &quot;Integer&quot;, &quot;DateTime&quot;], how_many_times_ive_done_this: 1 } post.save # Writes to the database. </pre> <p> This example shows us some of the types that are supported and serialized for you. Using the key we’ve defined, we can also find this object in our table:</p> <pre class="brush: ruby"> my_post = Forum.find(forum_uuid: uuid, post_id: 1) my_post.post_title # =&gt; &quot;Hello!&quot; my_post.created_at # =&gt; #&lt;DateTime: 2016-02-09T14:39:07-08:00 ((2457428j,81547s,0n),-28800s,2299161j)&gt; </pre> <p> You can use the same approach to save changes or, as shown here, you can delete the item from the table:</p> <pre class="brush: ruby"> my_post.delete! # =&gt; true </pre> <p> At this point, we know how to use <code>Aws::Record</code> to perform key-value store operations powered by DynamoDB and have an introduction to the types available for use in our tables.</p> <h3> Querying, Scanning, and Collections</h3> <p> Because it is likely that you’re probably doing Query and Scan operations in addition to key-value operations, <code>aws-record</code> provides support for integrating them with your model class.</p> <p> When you include the <code>Aws::Record</code> module, your model class is decorated with <code>#query</code> and <code>#scan</code> methods, which correspond to the AWS SDK for Ruby client operations. The response is wrapped in a collection enumerable for you. Consider the following basic scan operation:</p> <pre class="brush: ruby"> Forum.scan # =&gt; #&lt;Aws::Record::ItemCollection:0x007ffc293ec790 @search_method=:scan, @search_params={:table_name=&gt;&quot;Forum&quot;}, @model=Forum, @client=#&lt;Aws::DynamoDB::Client&gt;&gt; </pre> <p> No client call has been made yet: <code>ItemCollection</code> instances are lazy, and only make client calls only when needed. Because they provide an enumerable interface, you can use any of Ruby’s enumerable methods on your collection, and your result page is saved:</p> <pre class="brush: ruby"> resp = Forum.scan resp.take(1) # Makes a call to the underlying client. Returns a 'Forum' object. resp.take(1) # Same result, but does not repeat the client call. </pre> <p> Because the <code>Aws::Record::ItemCollection</code> uses version 2 ofthe AWS SDK for Ruby, pagination support is built-in. So, if your operation requires multiple DynamoDB client calls due to response truncation, <code>ItemCollection</code> will handle the calls required in your enumeration:</p> <pre class="brush: ruby"> def author_posts Forum.scan.inject({}) do |acc, post| author = post.author_username if acc[author] acc[author] += 1 else acc[author] = 1 end acc end end </pre> <p> The same applies for queries. Your query result will also be provided as an enumerable <code>ItemCollection</code>:</p> <pre class="brush: ruby"> def posts_by_forum(uuid) Forum.query( key_condition_expression: &quot;#A = :a&quot;, expression_attribute_names: { &quot;#A&quot; =&gt; &quot;forum_uuid&quot; }, expression_attribute_values: { &quot;:a&quot; =&gt; uuid } ) end </pre> <p> Given this functionality, you have the flexibility to mix and match Ruby’s enumerable functionality with DynamoDB filter expressions, for example, to curate your results. These two functions return the same set of responses:</p> <pre class="brush: ruby"> def posts_by_author_in_forum(uuid, author) posts_by_forum(uuid).select do |post| post.author_username == author end end def posts_by_author_in_forum_with_filter(uuid, author) Forum.query( key_condition_expression: &quot;#A = :a&quot;, filter_expression: &quot;#B = :b&quot;, expression_attribute_names: { &quot;#A&quot; =&gt; &quot;forum_uuid&quot;, &quot;#B&quot; =&gt; &quot;author_username&quot; }, expression_attribute_values: { &quot;:a&quot; =&gt; uuid, &quot;:b&quot; =&gt; author } ) end </pre> <h3> Support for Secondary Indexes</h3> <p> <code>Aws::Record</code> also supports both local and global secondary indexes. Consider this modified version of our Forum table:</p> <pre class="brush: ruby"> require 'aws-record' class IndexedForum include Aws::Record string_attr :forum_uuid, hash_key: true integer_attr :post_id, range_key: true string_attr :author_username string_attr :post_title string_attr :post_body datetime_attr :created_at map_attr :post_metadata global_secondary_index(:author, hash_key: :author_username, projection: { projection_type: &quot;INCLUDE&quot;, non_key_attributes: [&quot;post_title&quot;] } ) local_secondary_index(:by_date, range_key: :created_at, projection: { projection_type: &quot;ALL&quot; } ) end </pre> <p> You can see the table’s attributes are the same, but we’ve included a couple potentially useful indexes.</p> <ul> <li> <code>:author</code>: This uses the author name as a partition, which provides a way to search across forums by author user name without having to scan and filter. Take note of the projection, because your global secondary index results will only return the <code>:forum_uuid</code>, <code>:post_id</code>, <code>:author_username</code>, and <code>:post_title</code>. Other attributes will be missing from this projection, and you would have to hydrate your item by calling <code>#reload!</code> on the item instance.</li> <li> <code>:by_date</code>: This provides a way to sort and search within a forum by post creation date.</li> </ul> <p> To create this table with secondary indexes, you create a migration like we did before:</p> <pre class="brush: ruby"> require 'indexed_forum' migration = Aws::Record::TableMigration.new(IndexedForum) migration.create!( provisioned_throughput: { read_capacity_units: 10, write_capacity_units: 4 }, global_secondary_index_throughput: { author: { read_capacity_units: 5, write_capacity_units: 3 } } ) migration.wait_until_available </pre> <p> You can use either of these indexes with the query interface:</p> <pre class="brush: ruby"> require 'indexed_forum' def search_by_author(author) IndexedForum.query( index_name: &quot;author&quot;, key_condition_expression: &quot;#A = :a&quot;, expression_attribute_names: { &quot;#A&quot; =&gt; &quot;author_username&quot; }, expression_attribute_values: { &quot;:a&quot; =&gt; author } ) ) </pre> <p> Secondary indexes can be a powerful performance tool, and <code>aws-record</code> can simplify the process of managing them.</p> <h2> Get Involved!</h2> <p> Please download the gem, give it a try, and let us know what you think. This project is a work in progress, so we welcome feature requests, bug reports, and information about the kinds of problems you’d like to solve by using this gem. And, as with other SDKs and tools we produce, we’d also be happy to look at contributions.</p> <p> You can find the project on GitHub at <a href="https://github.com/awslabs/aws-sdk-ruby-record">https://github.com/awslabs/aws-sdk-ruby-record</a></p> <p> Please reach out and let us know what you think!</p> AWS SDK for Ruby Office Hour https://aws.amazon.com/blogs/developer/aws-sdk-for-ruby-office-hour/ Wed, 24 Jun 2015 21:07:08 +0000 6ef7a6aa8f899d2adca425e0167c03a2cf6adec4 The AWS SDKs and Tools team invites you to the first-ever online office hour hosted by the maintainers of the AWS SDK for Ruby. It will be held via Google Hangouts at&nbsp;11:00am-12:00pm PDT (UTC -7:00) on Tuesday 6/30. If you don’t have one already, you will need to create an account with Google to join […] <p> The AWS SDKs and Tools team invites you to the first-ever online office hour hosted by the maintainers of the AWS SDK for Ruby. It will be held via Google Hangouts at&nbsp;<b>11:00am-12:00pm PDT (UTC -7:00) on Tuesday 6/30</b>. If you don’t have one already, you will need to create an account with Google to join the video chat.</p> <p> This first office hour will be driven by customer questions. We expect to focus on questions about the SDK, but any questions related to Ruby development on AWS are welcome. We’re excited to meet you and help you be successful in developing Ruby applications on AWS!</p> <p> Please <a href="https://www.eventbrite.com/e/aws-sdk-for-ruby-office-hour-tickets-17516131220"><span class="s1">register for the event</span></a>, add it to your calendar, and join the office hour next Monday.</p> RailsConf 2015 Recap https://aws.amazon.com/blogs/developer/railsconf-2015-recap/ Thu, 21 May 2015 16:10:00 +0000 08789291237d18f7772531443a966d59c6f317fd 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 […] <p> 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.</p> <h2> Our Rails on Amazon Web Services Workshop</h2> <p> At RailsConf, we ran a workshop called <em>Deploy and Manage Ruby on Rails Apps on AWS</em>. 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.</p> <p> For those of you who could not make it, you can still give this workshop a try!</p> <ul> <li> Detailed step-by-step instructions, the same as we provided to attendees, are <a href="http://railsconf2015-aws.s3-website-us-east-1.amazonaws.com/">available here</a>.</li> <li> You can also follow along with the <a href="https://www.youtube.com/watch?v=OQoYTeGJYf4">presentation recording</a> on YouTube.</li> <li> Code for the sample app is available on <a href="https://github.com/awslabs/todo-app-railsconf">GitHub</a>.</li> <li> If you’d like to try using Amazon Relational Database Service instead of using AWS OpsWorks managed MySQL, you can reference our <a href="http://ruby.awsblog.com/post/Tx30I1YMLBH2TU8/Using-Amazon-RDS-with-Ruby-on-Rails-and-AWS-OpsWorks">blog post</a> on that topic as well.</li> </ul> <h2> Continuing the Conversation</h2> <p> We hope to see more of you on the conference trail again soon! Apropos of this, it is worth mentioning that <a href="https://reinvent.awsevents.com/">AWS re:Invent</a> registration is open at the time of writing. We will be there, and we hope to see you there!</p> Uploading Files to Amazon S3 https://aws.amazon.com/blogs/developer/uploading-files-to-amazon-s3/ Tue, 14 Apr 2015 18:04:13 +0000 8b1d54b4fdaba5dc660ac60991f545999f9a6c73 I blogged previously about downloading objects from Amazon S3 using the version 2 AWS SDK for Ruby. It was requested that I write about uploading objects as well. Managed File Uploads The simplest and most common task is upload a file from disk to a bucket in Amazon S3. This is very straightforward when using […] <p>I blogged previously about <a href="http://ruby.awsblog.com/post/Tx354Y6VTZ421PJ/-Downloading-Objects-from-Amazon-span-class-matches-S3-span-using-the-AWS-SDK-fo">downloading objects from Amazon S3</a> using the version 2 AWS SDK for Ruby. It was requested that I write about uploading objects as well.</p> <h2>Managed File Uploads</h2> <p>The simplest and most common task is upload a file from disk to a bucket in Amazon S3. This is very straightforward when using the resource interface for Amazon S3:</p> <pre class="brush: ruby">s3 = Aws::S3::Resource.new s3.bucket('bucket-name').object('key').upload_file('/source/file/path')</pre> <p>You can pass additional options to the <code>Resource</code> constructor and to <code>#upload_file</code>. This expanded example demonstrates configuring the resource client, uploading a public object and then generating a URL that can be used to download the object from a browser.</p> <pre class="brush: ruby">s3 = Aws::S3::Resource.new( credentials: Aws::Credentials.new('akid', 'secret'), region: 'us-west-1' ) obj = s3.bucket('bucket-name').object('key') obj.upload_file('/source/file/path', acl:'public-read') obj.public_url #=&gt; &quot;https://bucket-name.s3-us-west-1.amazonaws.com/key&quot;</pre> <p>This is the recommended method of using the SDK to upload files to a bucket. Using this approach has the following benefits:</p> <ul> <li>Manages multipart uploads for objects larger than 15MB.</li> <li>Correctly opens files in binary mode to avoid encoding issues.</li> <li>Uses multiple threads for uploading parts of large objects in parallel.</li> </ul> <h2>Other Methods</h2> <p>In addition to <code>Aws::S3::Object#upload_file</code>, you can upload an object using <code>#put</code> or using the multipart upload APIs.</p> <h3>PUT Object</h3> <p>For smaller objects, you may choose to use <code>#put</code> instead. The <code>#put</code> method accepts an optional body, which can be a string or any IO object.</p> <pre class="brush: ruby">obj = s3.bucket('bucket-name').object('key') # from a string obj.put(body:'Hello World!') # from an IO object File.open('/source/file', 'rb') do |file| obj.put(body:file) end</pre> <h3>Multipart APIs</h3> <p>I recommend you use <code>#upload_file</code> whenever possible. If you need to manage large object copies, then you will need to use the multipart interfaces. There are restrictions on the minimum file, and part sizes you should be aware of. Typically these are reserved for advanced use cases.</p> <h2>Feedback</h2> <p>I’d love to hear feedback. If you find the AWS SDK for Ruby lacks a utility for working with Amazon S3, I’d love to hear about it. Please feel free to open a <a href="https://github.com/aws/aws-sdk-ruby/issues">GitHub issue</a> or drop into our <a>Gitter channel</a>.</p> Verifying Amazon SNS Message Authenticity https://aws.amazon.com/blogs/developer/verifying-amazon-sns-message-authenticity/ Thu, 09 Apr 2015 18:04:20 +0000 468ee58478c525f206cd5b8fbb9904882e2c0c46 You can now use version 2 of the AWS SDK for Ruby to verify the signatures of Amazon SNS messages. To help prevent spoofing attacks, you should verify messages are sent by Amazon SNS. The new verifier follows the documented best practices for verification, including: Always use HTTPS when getting the certificate from Amazon SNS. […] <p>You can now use version 2 of the AWS SDK for Ruby to verify the signatures of Amazon SNS messages. To help prevent spoofing attacks, <strong>you should verify messages are sent by Amazon SNS</strong>.</p> <p>The new verifier follows the <a href="http://docs.aws.amazon.com/sns/latest/dg/SendMessageToHttp.verify.signature.html">documented best practices for verification</a>, including:</p> <ul> <li>Always use HTTPS when getting the certificate from Amazon SNS.</li> <li>Validate the authenticity of the certificate.</li> <li>Verify the certificate was received from Amazon SNS.</li> </ul> <h2>Basic Usage</h2> <p>Usage is straightforward. Construct a message verifier and call one of two methods. The given message body should be the JSON document string of the message.</p> <pre class="brush: ruby">verifier = Aws::SNS::MessageVerifier.new verifier.authentic?(message_body) #=&gt; returns true or false verifier.authenticate!(message_body) #=&gt; returns true or raises a VerificationError</pre> <p>You can use one instance of <code>Aws::SNS::MessageVerifier.new</code> to verify multiple messages. </p> <h2>Feedback</h2> <p>As always, we love to hear your feedback. It helps us prioritize our development efforts. In fact, this feature was added by customer request. Feel free to join our <a>Gitter channel</a> or open a <a href="https://github.com/aws/aws-sdk-ruby/issues">GitHub issue</a>.</p> Polling Messages from a Amazon SQS Queue https://aws.amazon.com/blogs/developer/polling-messages-from-a-amazon-sqs-queue/ Tue, 07 Apr 2015 17:17:31 +0000 fd2de45fd9fc7aac72aafe062e6b026a5f3a07ab We’ve recently added a utility class to the AWS SDK for Ruby that makes it easy to poll an Amazon SQS queue for messages. poller = Aws::SQS::QueuePoller.new(queue_url) poller.poll do |msg| puts msg.body end Messages are automatically deleted from the queue at the end of the block. This tool supports receiving and deleting messages in batches, […] <p>We’ve recently added a utility class to the AWS SDK for Ruby that makes it easy to poll an Amazon SQS queue for messages.</p> <pre class="brush: ruby">poller = Aws::SQS::QueuePoller.new(queue_url) poller.poll do |msg| puts msg.body end</pre> <p>Messages are automatically deleted from the queue at the end of the block. This tool supports receiving and deleting messages in batches, long-polling, client-side tracking of stats, and more.</p> <h2>Long Polling</h2> <p>By default, messages are received using long polling. This method will force a default <code>:wait_time_seconds</code> of 20 seconds. If you prefer to use the queue default wait time, then pass a <code>nil</code> value for <code>:wait_time_seconds</code>.</p> <pre class="brush: ruby"># disables 20 second default, use queue ReceiveMessageWaitTimeSeconds attribute poller.poll(wait_time_seconds:nil) do |msg| # ... end</pre> <p>When disabling <code>:wait_time_seconds</code> by passing <code>nil</code>, you must ensure the queue <code>ReceiveMessageWaitTimeSeconds</code> attribute is set to a non zero value, or you will be short polling. This will trigger significantly more API calls.</p> <h2>Batch Receiving Messages</h2> <p>You can specify a maximum number of messages to receive with each polling attempt via <code>:max_number_of_messages</code>. When this is set to a positive value, greater than 1, the block will receive an array of messages, instead of a single message.</p> <pre class="brush: ruby"># receives and yields up to 10 messages at a time poller.poll(max_number_of_messages:10) do |messages| messages.each do |msg| # ... end end</pre> <p>The maximum value for <code>:max_number_of_messages</code> is enforced by Amazon SQS.</p> <h2>Visibility Timeouts</h2> <p>When receiving messages, you have a fixed amount of time to process and delete each message before it is added back into the queue. This is the visibility timeout. By default, the queue’s <code>VisibilityTimeout</code> attribute is used. You can provide an alternative visibility timeout when polling.</p> <pre class="brush: ruby"># override queue visibility timeout poller.poll(visibility_timeout:10) do |msg| # do work ... end</pre> <p>You can reset the visibility timeout of a single message by calling <code>#change_message_visibility</code>. This is useful when you need more time to finish processing the message.</p> <pre class="brush: ruby">poller.poll do |msg| # do work ... # need more time for processing poller.change_message_visibility(msg, 60) # finish work ... end</pre> <p>If you change the visibility timeout of a message to zero, it will return to the queue immediately.</p> <h2>Deleting Messages</h2> <p>Messages are deleted from the queue when the block returns normally.</p> <pre class="brush: ruby">poller.poll do |msg| # do work end # messages deleted here</pre> <p>You can skip message deletion by passing <code>skip_delete: true</code>. This allows you to manually delete the messages using {#delete<em>message}, or {#delete</em>messages}.</p> <pre class="brush: ruby"># single message poller.poll(skip_delete: true) do |msg| poller.delete_message(msg) # if successful end # message batch poller.poll(skip_delete: true, max_number_of_messages:10) do |messages| poller.delete_messages(messages) end</pre> <p>Another way to manage message deletion is to throw <code>:skip_delete</code> from the poll block. You can use this to choose when a message, or message batch is deleted on an individual basis:</p> <pre class="brush: ruby">poller.poll do |msg| begin # do work rescue # unexpected error occurred while processing messages, # log it, and skip delete so it can be re-processed later throw :skip_delete end end</pre> <h2>Terminating the Polling Loop</h2> <p>By default, polling will continue indefinitely. You can stop the poller by providing an idle timeout or by throwing <code>:stop_polling</code> from the {#before_request} callback.</p> <h3>:idle_timeout</h3> <p>This is a configurable, maximum number of seconds to wait for a new message before the polling loop exists. By default, there is no idle timeout.</p> <pre class="brush: ruby"># stops polling after a minute of no received messages poller.poll(idle_timeout: 60) do |msg| # ... end</pre> <h3>:stop_polling</h3> <p>If you want more fine-grained control, you can configure a before request callback to trigger before each long poll. Throwing <code>:stop_polling</code> from this callback will cause the poller to exit normally without making the next request.</p> <pre class="brush: ruby"># stop after processing 100 messages poller.before_request do |stats| throw :stop_polling if stats.receive_message_count &gt;= 100 end poller.poll do |msg| # do work ... end</pre> <h2>Tracking Progress</h2> <p>The poller will automatically track a few statistics client-side in a PollerStats object. You can access the poller stats three ways:</p> <ul> <li>The first block argument of {#before_request}</li> <li>The second block argument of {#poll}.</li> <li>The return value from {#poll}.</li> </ul> <p>Here are examples of accessing the statistics.</p> <ul> <li> <p>Configure a {#before_request} callback.</p> <pre class="brush: ruby">poller.before_reqeust do |stats| logger.info(&quot;requests: #{stats.request_count}&quot;) logger.info(&quot;messages: #{stats.received_message_count}&quot;) logger.info(&quot;last-timestamp: #{stats.last_message_received_at}&quot;) end</pre> </li> <li> <p>Accept a second argument in the poll block, for example:</p> <pre class="brush: ruby">poller.poll do |msg, stats| logger.info(&quot;requests: #{stats.request_count}&quot;) logger.info(&quot;messages: #{stats.received_message_count}&quot;) logger.info(&quot;last-timestamp: #{stats.last_message_received_at}&quot;) end</pre> </li> <li> <p>Return value:</p> <pre class="brush: ruby">stats = poller.poll(idle_timeout:10) do |msg| # do work ... end logger.info(&quot;requests: #{stats.request_count}&quot;) logger.info(&quot;messages: #{stats.received_message_count}&quot;) logger.info(&quot;last-timestamp: #{stats.last_message_received_at}&quot;)</pre> </li> </ul> <h2>Feedback</h2> <p>Let us know what you think about the new queue poller. Join the conversation in our <a href="http://gitter.im/aws/aws-sdk-ruby">Gitter channel</a> or open a <a href="https://github.com/aws/aws-sdk-ruby/issues">GitHub issue</a>.</p> Announcing the aws-sdk-rails Gem https://aws.amazon.com/blogs/developer/announcing-the-aws-sdk-rails-gem/ Fri, 20 Mar 2015 16:04:21 +0000 15b108f81414b97a824998548b3945c9a9f1416f 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 […] <p> 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.</p> <p> Today, we’re excited to announce the release of the aws-sdk-rails gem, available now via <a href="https://rubygems.org/gems/aws-sdk-rails">RubyGems</a> and, of course, on <a href="https://github.com/aws/aws-sdk-rails">GitHub</a>.</p> <p> To get started, add the <code>aws-sdk-rails</code> gem to your Gemfile:</p> <pre class="brush: ruby"> gem 'aws-sdk-rails', '~&gt; 1.0' </pre> <h2> ActionMailer and Amazon Simple Email Service (SES)</h2> <p> The gem will automatically configure Rails to include an <code>:aws_sdk</code> delivery method for ActionMailer, that uses Amazon SES as a backend. It is simple to configure Rails to use this delivery method:</p> <pre class="brush: ruby"> # config/application.rb config.action_mailer.delivery_method = :aws_sdk </pre> <p> The aws-sdk-rails gem will use the AWS SDK for Ruby V2’s SES client automatically for any mail delivery event.</p> <h2> Logging</h2> <p> The gem will automatically wire the AWS SDK for Ruby’s logger to use <code>Rails.logger</code> by default.</p> <p> You can customize the SDK log level and an optional log formatter in a config initializer:</p> <pre class="brush: ruby"> # config/initializers/aws-sdk.rb # log level defaults to :info Aws.config[:log_level] = :debug </pre> <p> It is important to understand that <strong>all SDK log messages are logged at the same log level</strong>. 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 <code>:debug</code> as shown above, and set the Rails logger to show debug in development.</p> <h2> Credentials</h2> <p> The AWS SDK for Ruby will attempt locate credentials by searching the following locations:</p> <ul> <li> <code>ENV['AWS_ACCESS_KEY_ID']</code> and <code>ENV['AWS_SECRET_ACCESS_KEY']</code></li> <li> The shared credentials ini file at ~/.aws/credentials</li> <li> From an instance profile when running on Amazon EC2</li> </ul> <p> If you need to manually configure credentials, you should add them to your initializer:</p> <pre class="brush: ruby"> # config/initializers/aws-sdk.rb Aws.config[:credentials] = Aws::Credentials.new(access_key, secret) </pre> <p> <a href="http://docs.aws.amazon.com/sdkforruby/api/index.html#Credentials">Learn more about credentials in the AWS SDK for Ruby V2</a>.</p> <p> <strong>Never commit your credentials to source control.</strong> Besides being a security risk, it makes it very difficult to rotate your credentials.</p> <h2> Available Now</h2> <p> The <code>aws-sdk-rails</code> gem is available now.</p> <p> As always, we’d love to hear your feedback, and welcome any Issues or Pull Requests at the <a href="http://github.com/aws/aws-sdk-rails">aws-sdk-rails GitHub repo</a>.</p> Amazon DynamoDB Document API in Ruby (Part 3 – Update Expressions) https://aws.amazon.com/blogs/developer/amazon-dynamodb-document-api-in-ruby-part-3-update-expressions/ Tue, 24 Feb 2015 23:01:07 +0000 673310ffe84e46a32c8cf99b4da3903b2762398a As we showed in previous posts, it’s easy to put JSON items into Amazon DynamoDB, retrieve specific attributes with projection expressions, and fetch only data that meet some criteria with condition expressions. Now, let’s take a look at how we can conditionally modify existing items with Update Expressions. (Note: this code uses the same ProductCatalog […] <p>As we showed in previous posts, it’s easy to put JSON items into Amazon DynamoDB, retrieve specific attributes with projection expressions, and fetch only data that meet some criteria with condition expressions. Now, let’s take a look at how we can conditionally modify existing items with <a href="http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.Modifying.html#Expressions.Modifying.UpdateExpressions">Update Expressions</a>. (Note: this code uses the same ProductCatalog table we used in Parts 1 and 2).</p> <p>In the following examples, we use the following helper method to perform conditional updates. It performs the UpdateItem operation with return_values set to return the old item. We also use the GetItem operation so the method can return both the old and new items for us to compare. (If the update condition in the request is not met, then the method sets the returned old item to nil.)</p> <pre class="brush: ruby">def do_update_item(key_id, update_exp, condition_exp, exp_attribute_values) begin old_result = @dynamodb.update_item( :update_expression =&gt; update_exp, :condition_expression =&gt; condition_exp, :expression_attribute_values =&gt; exp_attribute_values, :table_name =&gt; &quot;ProductCatalog&quot;, :key =&gt; { :Id =&gt; key_id }, :return_values =&gt; &quot;ALL_OLD&quot;, ).data.attributes rescue Aws::DynamoDB::Errors::ConditionalCheckFailedException old_result = nil puts &quot;Condition not met&quot; end new_result = @dynamodb.get_item( :table_name =&gt; &quot;ProductCatalog&quot;, :key =&gt; { :Id =&gt; key_id }, :consistent_read =&gt; true ).data.item return old_result, new_result end </pre> <h2>Using Conditional Update Expressions</h2> <p>Updates in DynamoDB are atomic. This allows applications to concurrently update items without worrying about conflicts occurring. For example, the following code demonstrates maintaining a MAX value in DynamoDB with a conditional update using SET. Note that, because DynamoDB is schema-less, we don’t need to define the HighestRating attribute beforehand. Instead, we create it on the first call.</p> <pre class="brush: ruby"># storing a &quot;max&quot; value with conditional SET # SET attribute if doesn't exist, otherwise SET if stored highest rating &lt; this rating def update_highest_rating(rating) do_update_item(303, &quot;SET HighestRating = :val&quot;, &quot;attribute_not_exists(HighestRating) OR HighestRating &lt; :val&quot;, { &quot;:val&quot; =&gt; rating } ) end # multiple threads trying to SET highest value (ranging from 0 to 10) threads = [] (0..10).to_a.shuffle.each { |i| # some number of &quot;Condition not met&quot; depending on shuffled order puts i threads[i] = Thread.new { update_highest_rating(i) } } threads.each {|t| t.join} # fetch the item and examine the HighestRating stored puts &quot;Max = #{@dynamodb.get_item( :table_name =&gt; &quot;ProductCatalog&quot;, :key =&gt; { :Id =&gt; 303 } ).data.item[&quot;HighestRating&quot;].to_i}&quot; # Max = 10 </pre> <p>We can also use update expressions to atomically maintain a count and add to a set:</p> <pre class="brush: ruby"># ADD to intialize/increment and add to set threads = [] 20.times do |i| threads[i] = Thread.new { do_update_item(303, &quot;ADD TimesViewed :val, Tags :was_here&quot;, nil, # no condition expression { # Each of the 20 threads increments by 1 &quot;:val&quot; =&gt; 1, # Each thread adds to the tag set # Note: type must match stored attribute's type &quot;:was_here&quot; =&gt; Set.new([&quot;#Thread#{i}WasHere&quot;]) } ) } end threads.each {|t| t.join} # fetch the item and examine the TimesViewed attribute item = @dynamodb.get_item( :table_name =&gt; &quot;ProductCatalog&quot;, :key =&gt; { :Id =&gt; 303 } ).data.item puts &quot;TimesViewed = #{item[&quot;TimesViewed&quot;].to_i}&quot; # TimesViewed = 20 puts &quot;Tags = #{item[&quot;Tags&quot;].inspect}&quot; # Tags = #&lt;Set: {&quot;#Mars&quot;, &quot;#MarsCuriosity&quot;, &quot;#StillRoving&quot;, ..each thread was here...}&gt; </pre> <p>Similarly, we can decrement the count and remove from the set to undo our previous operations.</p> <pre class="brush: ruby"># Undo the views and set adding that we just performed threads = [] 20.times do |i| threads[i] = Thread.new { do_update_item(303, &quot;ADD TimesViewed :val DELETE Tags :was_here&quot;, nil, # no condition expression { # Each of the 20 threads decrements by 1 &quot;:val&quot; =&gt; -1, # Each thread removes from the tag set # Note: type must match stored attribute's type &quot;:was_here&quot; =&gt; Set.new([&quot;#Thread#{i}WasHere&quot;]) } ) } end threads.each {|t| t.join} # fetch the item and examine the TimesViewed attribute item = @dynamodb.get_item( :table_name =&gt; &quot;ProductCatalog&quot;, :key =&gt; { :Id =&gt; 303 } ).data.item puts &quot;TimesViewed = #{item[&quot;TimesViewed&quot;].to_i}&quot; # TimesViewed = 0 puts &quot;Tags = #{item[&quot;Tags&quot;].inspect}&quot; # Tags = #&lt;Set: {&quot;#Mars&quot;, &quot;#MarsCuriosity&quot;, &quot;#StillRoving&quot;}&gt; </pre> <p>We can also use the REMOVE keyword to delete attributes, such as the HighestRating and TimesViewed attributes we added in the previous code.</p> <pre class="brush: ruby"># removing attributes from items old_and_new = do_update_item(303, &quot;REMOVE HighestRating, TimesViewed&quot;, nil, # no condition expression nil, # no attribute expression values ) puts &quot;OLD HighestRating is nil ? #{old_and_new[0][&quot;HighestRating&quot;] == nil}&quot; #=&gt; false puts &quot;OLD TimesViewed is nil ? #{old_and_new[0][&quot;TimesViewed&quot;] == nil}&quot; #=&gt; false puts &quot;NEW HighestRating is nil ? #{old_and_new[1][&quot;HighestRating&quot;] == nil}&quot; #=&gt; true puts &quot;NEW TimesViewed is nil ? #{old_and_new[1][&quot;TimesViewed&quot;] == nil}&quot; #=&gt; true </pre> <h2>Conclusion</h2> <p>We hope this series was helpful in demonstrating expressions and how they allow you to interact with DynamoDB more flexibly than before. We’re always interested in hearing what developers would like to see in the future, so let us know what you think in the comments or through our <a href="https://forums.aws.amazon.com/forum.jspa?forumID=131">forums</a>!</p> Amazon DynamoDB Document API in Ruby (Part 2 – Condition Expressions) https://aws.amazon.com/blogs/developer/amazon-dynamodb-document-api-in-ruby-part-2-condition-expressions/ Wed, 18 Feb 2015 21:28:00 +0000 21319c3f45ab4c10a23b5e6574d35b0227a35da5 As we showed in the previous post, it’s easy to put JSON items into Amazon DynamoDB and retrieve specific attributes with projection expressions. Condition Expressions provide a more flexible and SQL-like way to retrieve only the items you want from DynamoDB. First, let’s put a few more items into DynamoDB using a BatchWriteItem operation. (Note: […] <p>As we showed in the previous post, it’s easy to put JSON items into Amazon DynamoDB and retrieve specific attributes with projection expressions. <a href="http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.SpecifyingConditions.html#Expressions.SpecifyingConditions.ConditionExpressions">Condition Expressions</a> provide a more flexible and SQL-like way to retrieve only the items you want from DynamoDB. First, let’s put a few more items into DynamoDB using a BatchWriteItem operation. (Note: this code uses the same ProductCatalog table we used in Part 1)</p> <pre class="brush: ruby"># add some more items @dynamodb.batch_write_item( :request_items =&gt; { &quot;ProductCatalog&quot; =&gt; [ {:put_request =&gt; { :item =&gt; { Id: 300, Title: &quot;Sojourner&quot;, Description: &quot;Mars Pathfinder robotic Mars rover&quot;, Price: BigDecimal.new(&quot;2.65e8&quot;), LaunchDate: { M: 12, D: 4, Y: 1996 }, LostCommunicationDate: { M: 9, D: 27, Y: 1997 }, Features: { Rover: true, }, NumberInStock: 10, OrdersPlaced: 3, Tags: [&quot;#Mars&quot;, &quot;#InStarTrekSeason4&quot;, &quot;#InRedPlant2000&quot;, &quot;#LostComms&quot;], }}}, {:put_request =&gt; { :item =&gt; { Id: 301, Title: &quot;Spirit&quot;, Description: &quot;Mars Exploration Rover – A&quot;, Price: BigDecimal.new(&quot;4.1e8&quot;), LaunchDate: { M: 6, D: 10, Y: 2003 }, LostCommunicationDate: { M: 3, D: 22, Y: 2010 }, Features: { Rover: true, }, NumberInStock: 10, OrdersPlaced: 5, Tags: Set.new([&quot;#Mars&quot;, &quot;#StuckOnMars&quot;, &quot;#LostComms&quot;]), }}}, {:put_request =&gt; { :item =&gt; { Id: 302, Title: &quot;Opportunity&quot;, Description: &quot;Mars Exploration Rover – B&quot;, Price: BigDecimal.new(&quot;4.1e8&quot;), LaunchDate: { M: 7, D: 7, Y: 2003 }, LostCommunicationDate: nil, Features: { Rover: true, }, NumberInStock: 10, OrdersPlaced: 10, Tags: Set.new([&quot;#Mars&quot;, &quot;#StillRoving&quot;]), }}}, {:put_request =&gt; { :item =&gt; { Id: 303, Title: &quot;Curiosity&quot;, Description: &quot;car-sized robotic rover&quot;, Price: BigDecimal.new(&quot;2.5e9&quot;), LaunchDate: { M: 11, D: 26, Y: 2011 }, LostCommunicationDate: nil, Features: { Rover: true, RoboticArm: true, }, NumberInStock: 0, OrdersPlaced: 30, Tags: Set.new([&quot;#Mars&quot;, &quot;#MarsCuriosity&quot;, &quot;#StillRoving&quot;]), }}}, ] } ) </pre> <h2>Using Condition Expressions</h2> <p>We could also use condition expressions on the results of Query, but since we’re using a simple data model (only have hash key on product Id), we demonstrate this with scans. We use the following helper method to perform the scan and format the product titles returned:</p> <pre class="brush: ruby">def do_scan(filter_exp, exp_attribute_values) result = @dynamodb.scan( :expression_attribute_values =&gt; exp_attribute_values, :filter_expression =&gt; filter_exp, # Condition Expressions are supplied through the FilterExpression parameter :projection_expression =&gt; &quot;Title&quot;, :table_name =&gt; &quot;ProductCatalog&quot; ).data.items # format all retrieved titles into a single line return &quot;scan retrieved: #{(result.map { |item| item[&quot;Title&quot;] }).join(&quot;, &quot;)}&quot; end </pre> <p>Let’s look at some example expressions and the results they return from our current ProductCatalog table:</p> <pre class="brush: ruby"># All products that don't have a launch month of November (11) puts do_scan( &quot;LaunchDate.M &lt;&gt; :m&quot;, { &quot;:m&quot; =&gt; 11 } ) # scan retrieved: 20-Bicycle 205, Opportunity, Spirit, Sojourner # All rover products that don't have a launch month of November puts do_scan( &quot;attribute_exists(Features.Rover) AND LaunchDate.M &lt;&gt; :m&quot;, { &quot;:m&quot; =&gt; 11, } ) # scan retrieved: Opportunity, Spirit, Sojourner # Non-rovers puts do_scan( &quot;attribute_not_exists(Features.Rover)&quot;, nil ) # scan retrieved: 20-Bicycle 205 # mid-range rovers or inexpensive products puts do_scan( &quot;(Price BETWEEN :low AND :high) OR Price &lt; :verylow&quot;, { &quot;:verylow&quot; =&gt; BigDecimal.new(&quot;1e8&quot;), &quot;:low&quot; =&gt; BigDecimal.new(&quot;3e8&quot;), &quot;:high&quot; =&gt; BigDecimal.new(&quot;5e8&quot;) } ) # scan retrieved: 20-Bicycle 205, Opportunity, Spirit # within-Item referencing: more orders placed than in stock puts do_scan( &quot;OrdersPlaced &gt; NumberInStock&quot;, nil ) # scan retrieved: Curiosity # string prefixing puts do_scan( &quot;begins_with(Title, :s)&quot;, { &quot;:s&quot; =&gt; &quot;S&quot;, } ) # scan retrieved: Spirit, Sojourner # contains puts do_scan( &quot;contains(Tags, :tag1) AND contains(Tags, :tag2)&quot;, { &quot;:tag1&quot; =&gt; &quot;#StuckOnMars&quot;, &quot;:tag2&quot; =&gt; &quot;#LostComms&quot;, } ) # scan retrieved: Spirit # contains (Note: &quot;Tags&quot; is a list for Sojourner) puts do_scan( &quot;contains(Tags, :tag1)&quot;, { &quot;:tag1&quot; =&gt; &quot;#LostComms&quot;, } ) # scan retrieved: Spirit, Sojourner # in operator puts do_scan( &quot;Id in (:id1, :id2)&quot;, { &quot;:id1&quot; =&gt; 302, &quot;:id2&quot; =&gt; 303, } ) # scan retrieved: Curiosity, Opportunity # equivalently, with parentheses puts do_scan( &quot;(Id = :id1) OR (Id = :id2)&quot;, { &quot;:id1&quot; =&gt; 302, &quot;:id2&quot; =&gt; 303, } ) # scan retrieved: Curiosity, Opportunity </pre> <h2>Next Steps</h2> <p>As you can see, condition expressions enable you to write more concise code to retrieve data. They also provide querying capabilities unavailable with the original access model such as within-Item references and more flexible conditions with parentheses. In an upcoming blog post, we’ll take a closer look at how we can update existing data through <a href="http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.Modifying.html">update expressions</a>.</p> Amazon DynamoDB Document API in Ruby (Part 1 – Projection Expressions) https://aws.amazon.com/blogs/developer/amazon-dynamodb-document-api-in-ruby-part-1-projection-expressions/ Fri, 13 Feb 2015 00:00:22 +0000 c9daaf5100683f7441e08c4ed8856b36e64594ac Amazon DynamoDB launched JSON Document Support along with several improvements to the DynamoDB API. This post is part of a series where we’ll explore these features in more depth with the AWS SDK for Ruby V2. In particular, this post focuses on putting items into DynamoDB using the Ruby SDK and controlling the data we […] <p>Amazon DynamoDB launched <a href="http://aws.amazon.com/blogs/aws/dynamodb-update-json-and-more/">JSON Document Support</a> along with several improvements to the <a href="http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/Welcome.html">DynamoDB API</a>. This post is part of a series where we’ll explore these features in more depth with the <a href="http://docs.aws.amazon.com/sdkforruby/api/frames.html">AWS SDK for Ruby V2</a>. In particular, this post focuses on putting items into DynamoDB using the Ruby SDK and controlling the data we get back with projection expressions. At the end of the post, we also provide some helpful information for getting started with DynamoDB Local.</p> <h2>Putting JSON data into DynamoDB</h2> <p>DynamoDB now supports the following new <a href="http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_AttributeValue.html">data types</a>: Maps, Lists, Booleans, and Nulls. Suppose we have a DynamoDB table for products with a hash key on an &quot;Id&quot; attribute. It’s easy to store such data into DynamoDB with native Ruby types:</p> <pre class="brush: ruby"># put a JSON item item = { Id: 205, # hash key Title: &quot;20-Bicycle 205&quot;, Description: &quot;205 description&quot;, BicycleType: &quot;Hybrid&quot;, Brand: &quot;Brand-Company C&quot;, Price: 500, Gender: &quot;B&quot;, Color: Set.new([&quot;Red&quot;, &quot;Black&quot;]), ProductCategory: &quot;Bike&quot;, InStock: true, QuantityOnHand: nil, NumberSold: BigDecimal.new(&quot;1E4&quot;), RelatedItems: [ 341, 472, 649 ], Pictures: { # JSON Map of views to url String FrontView: &quot;http://example.com/products/205_front.jpg&quot;, RearView: &quot;http://example.com/products/205_rear.jpg&quot;, SideView: &quot;http://example.com/products/205_left_side.jpg&quot;, }, ProductReviews: { # JSON Map of stars to List of review Strings FiveStar: [ &quot;Excellent! Can't recommend it highly enough! Buy it!&quot;, &quot;Do yourself a favor and buy this.&quot; ], OneStar: [ &quot;Terrible product! Do not buy this.&quot; ] } } dynamodb.put_item(:table_name =&gt; &quot;ProductCatalog&quot;, :item =&gt; item) </pre> <h2>Getting data from DynamoDB using projection expressions</h2> <p>Since DynamoDB now supports more interesting data types, we’ve also added <a href="http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.AccessingItemAttributes.html#Expressions.AccessingItemAttributes.ProjectionExpressions">projection expressions</a> and <a href="http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.AccessingItemAttributes.html#ExpressionAttributeNames">expression attribute names</a> to make it easier to retrieve only the attributes we want:</p> <pre class="brush: ruby"># get only the attributes we want with projection expressions item = dynamodb.get_item( :table_name =&gt; &quot;ProductCatalog&quot;, # Get the item with Id == 205 :key =&gt; { :Id =&gt; 205 }, # for less typing, use expression attribute names to substitute # &quot;ProductReviews&quot; with &quot;#pr&quot; and &quot;RelatedItems&quot; with &quot;#ri&quot; :expression_attribute_names =&gt; { &quot;#pr&quot; =&gt; &quot;ProductReviews&quot;, &quot;#ri&quot; =&gt; &quot;RelatedItems&quot;, }, # get Price, Color, FiveStar reviews, 0th and 2nd related items :projection_expression =&gt; &quot;Price, Color, #pr.FiveStar, #ri[0], #ri[2], #pr.NoStar, #ri[4]&quot; # try projecting non-existent attributes too ).data.item puts item[&quot;Price&quot;].to_i # 500 puts item[&quot;Color&quot;].inspect # #&lt;Set: {&quot;Black&quot;, &quot;Red&quot;}&gt; puts item[&quot;ProductReviews&quot;][&quot;FiveStar&quot;][0] # Excellent! Can't recommend it highly enough! Buy it! puts item[&quot;ProductReviews&quot;][&quot;FiveStar&quot;][1] # Do yourself a favor and buy this. puts item[&quot;ProductReviews&quot;][&quot;OneStar&quot;].inspect # nil (because we only projected FiveStar reviews) puts item[&quot;ProductReviews&quot;][&quot;NoStar&quot;].inspect # nil (because no NoStar reviews) puts item[&quot;RelatedItems&quot;] # 0.341E3 (0th element) # 0.649E3 (2nd element) puts item[&quot;RelatedItems&quot;].size # 2 (non-existent 4th element not present) </pre> <h2>Next Steps</h2> <p>As you can see, it’s easy to put and get items in DynamoDB with the AWS SDK for Ruby. In upcoming blog posts, we’ll take a closer look at expressions for <a href="http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.SpecifyingConditions.html">filtering</a> and <a href="http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.Modifying.html">updating</a> data.</p> <p>Feel free to get started on <a href="http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Tools.DynamoDBLocal.html">DynamoDB Local</a> with the following code (note that it uses the <a href="http://docs.aws.amazon.com/AWSSdkDocsRuby/latest//DeveloperGuide/prog-basics-creds.html">credentials file approach</a> for specifying AWS credentials):</p> <pre class="brush: ruby">#! /usr/bin/ruby require &quot;set&quot; require &quot;bigdecimal&quot; require &quot;aws-sdk-core&quot; # Configure SDK # use credentials file at .aws/credentials Aws.config[:credentials] = Aws::SharedCredentials.new Aws.config[:region] = &quot;us-west-2&quot; # point to DynamoDB Local, comment out this line to use real DynamoDB Aws.config[:dynamodb] = { endpoint: &quot;http://localhost:8000&quot; } dynamodb = Aws::DynamoDB::Client.new ## Create the table if it doesn't exist begin dynamodb.describe_table(:table_name =&gt; &quot;ProductCatalog&quot;) rescue Aws::DynamoDB::Errors::ResourceNotFoundException dynamodb.create_table( :table_name =&gt; &quot;ProductCatalog&quot;, :attribute_definitions =&gt; [ { :attribute_name =&gt; :Id, :attribute_type =&gt; :N } ], :key_schema =&gt; [ { :attribute_name =&gt; :Id, :key_type =&gt; :HASH } ], :provisioned_throughput =&gt; { :read_capacity_units =&gt; 1, :write_capacity_units =&gt; 1, } ) # wait for table to be created puts &quot;waiting for table to be created...&quot; dynamodb.wait_until(:table_exists, table_name: &quot;ProductCatalog&quot;) puts &quot;table created!&quot; end </pre> Announcing V2 of the AWS SDK for Ruby https://aws.amazon.com/blogs/developer/announcing-v2-of-the-aws-sdk-for-ruby/ Thu, 05 Feb 2015 23:46:12 +0000 0c406e504cc34379f57f28fecea7ed193ffa32ef I am excited to announce today’s stable release of version 2 of the AWS SDK for Ruby. It is available now as the aws-sdk gem on RubyGems. Features Version 2 of the AWS SDK for Ruby, the aws-sdk gem, provides a number of powerful features for developers including: Support for 40+ services Resource interfaces for […] <p>I am excited to announce today’s stable release of version 2 of the AWS SDK for Ruby. It is available now as the <code>aws-sdk</code> gem on <a href="https://rubygems.org/gems/aws-sdk">RubyGems</a>.</p> <h2>Features</h2> <p>Version 2 of the AWS SDK for Ruby, the <code>aws-sdk</code> gem, provides a number of powerful features for developers including:</p> <ul> <li><a href="https://github.com/aws/aws-sdk-core-ruby#supported-services">Support for 40+ services</a></li> <li><a href="http://ruby.awsblog.com/post/Tx1H87IVGVUMIB5/Using-Resources">Resource interfaces for 7 services</a></li> <li><a href="http://ruby.awsblog.com/post/Tx15V81MLPR8D73/Client-Response-Stubs">Client response stubs</a></li> <li><a href="http://ruby.awsblog.com/post/Tx12723S1962YKG/Waiters">Waiters</a></li> <li><a href="http://ruby.awsblog.com/post/Tx2K7WCKKXEDCQT/Response-Paging">Response paging</a></li> <li><a href="http://ruby.awsblog.com/post/Tx1Z3OWVIQBIW1W/Parameter-Validation">Improved parameter validation</a></li> <li><a href="http://ruby.awsblog.com/post/Tx26M4PHIB2YE35/-Flexible-Gem-span-class-matches-Dependencies-span">Flexible gem dependencies</a></li> <li><a href="http://ruby.awsblog.com/post/Tx1PD3FWWRIG0VN/AWS-SDK-Core-Response-Structures">Structured response data</a></li> <li><a href="http://docs.aws.amazon.com/sdkforruby/api/frames.html">Improved API reference documentation with examples</a></li> <li><a href="http://ruby.awsblog.com/post/Tx2I4U7QAOJYNDY/-Ruby-SDK-Version-2-and-span-class-matches-Memoization-span">Aws.memoize no longer needed</a></li> <li>Intelligent credential management</li> <li>Extensible via plugins and custom request handlers</li> </ul> <h2>Upgrading</h2> <p>Version 2 of the AWS SDK for Ruby uses a different namespace, making it possible to use version 1 and version 2 in the same application.</p> <pre class="brush: ruby"># Gemfile gem 'aws-sdk', '~&gt; 2' gem 'aws-sdk-v1' # code require 'aws-sdk-v1' require 'aws-sdk' ec2_v1 = AWS::EC2.new # v1 ec2_v2 = Aws::EC2::Resource.new # v2 </pre> <p>This allows you to start using the version 2 SDK today without changing existing code.</p> <h2>Feedback</h2> <p>Please share your questions, comments, issues, etc. with us on <a href="https://github.com/aws/aws-sdk-ruby">GitHub</a>. You can also catch us in our <a href="https://gitter.im/aws/aws-sdk-ruby">Gitter channel</a>.</p> Upcoming Stable Release of AWS SDK for Ruby – Version 2 https://aws.amazon.com/blogs/developer/upcoming-stable-release-of-aws-sdk-for-ruby-version-2/ Wed, 28 Jan 2015 17:48:41 +0000 32f6bef5950b11544dd089a2033f8edd7cfb5727 We plan to release version 2 of the AWS SDK for Ruby next week. We will remove the preview flag from the 2.0 version of aws-sdk. Specify Your Version Dependencies The AWS SDK for Ruby uses semantic versioning. Updates within version 1 are backwards compatible. Version 2 of the aws-sdk gem is not backwards compatible. […] <p> We plan to release version 2 of the AWS SDK for Ruby next week. We will remove the preview flag from the 2.0 version of <code>aws-sdk</code>.</p> <h2> Specify Your Version Dependencies</h2> <p> The AWS SDK for Ruby uses <a href="http://semver.org/">semantic versioning</a>. Updates within version 1 are backwards compatible.</p> <p> <strong>Version 2 of the <em>aws-sdk</em> gem is not backwards compatible.</strong></p> <p> If you depend on the <code>aws-sdk</code> gem today, and do not specify the major version, please add this now. If not, you may run into issues when you bundle update.</p> <pre class="brush: ruby"> # Gemfile gem 'aws-sdk', '&lt; 2.0' # gemspec spec.add_dependency('aws-sdk', '&lt; 2.0') </pre> <h2> NameError: uninitialized constant AWS</h2> <p> If you receive this error, you likely have a dependency on <code>aws-sdk</code> and have updated so that you now have version 2 installed. Version 2 uses a different module name, so it does not define <code>AWS</code>.</p> <p> To resolve this issue, specify your version dependency as instructed above.</p> <h2> Using Both Versions</h2> <p> The following diagram shows how the version 1 and version 2 gems are organized.</p> <p> <img alt="" src="https://dmhnzl5mp9mj6.cloudfront.net/ruby_awsblog/images/v1-v2-diagram-1.png" style="width: 400px;height: 298px" /></p> <p> The <code>aws-sdk</code> gem is empty, and simply requires version 1 or version 2 specific gems. This allows you to install version 1 and version 2 in the same application.</p> <h3> Option A, for existing users</h3> <pre class="brush: ruby"> # Gemfile gem 'aws-sdk', '~&gt; 1' gem 'aws-sdk-resources', '~&gt; 2' # in code require 'aws-sdk' require 'aws-sdk-resources' </pre> <h3> Option B, for new users</h3> <pre class="brush: ruby"> # Gemfile gem 'aws-sdk-v1' gem 'aws-sdk', '~&gt; 2' # in code require 'aws-sdk-v1' require 'aws-sdk' </pre> <h2> Attention Library Authors</h2> <p> If you maintain a gem that has a dependency on version 1 of <code>aws-sdk</code>, I strongly recommend that you replace it with a dependency on <code>aws-sdk-v1</code>. This allows end users to require version 2 of <code>aws-sdk</code>.</p> <p> Please report any issues you have on our <a href="https://github.com/aws/aws-sdk-ruby">GitHub repository</a>.</p> Using Amazon RDS with Ruby on Rails and AWS OpsWorks https://aws.amazon.com/blogs/developer/using-amazon-rds-with-ruby-on-rails-and-aws-opsworks/ Wed, 10 Dec 2014 17:20:18 +0000 303994a50b9957f57d351e04a2398cdc7d14d343 Earlier in this blog series, we showed you how to deploy a Ruby on Rails application to Amazon Web Services using AWS OpsWorks. In that example, we used an OpsWorks-managed MySQL database run on an Amazon EC2 instance. One common piece of feedback on that post was a desire to see how you can set […] <p> <a href="http://ruby.awsblog.com/post/Tx7FQMT084INCR/Deploying-Ruby-on-Rails-Applications-to-AWS-OpsWorks">Earlier in this blog series</a>, we showed you how to deploy a Ruby on Rails application to Amazon Web Services using AWS OpsWorks. In that example, we used an OpsWorks-managed MySQL database run on an Amazon EC2 instance. One common piece of feedback on that post was a desire to see how you can set up your stack with Amazon RDS. Today, we are going to show you how.</p> <h2> Prerequisites</h2> <p> We are going to assume you’re familiar with our <a href="http://ruby.awsblog.com/post/Tx7FQMT084INCR/Deploying-Ruby-on-Rails-Applications-to-AWS-OpsWorks">earlier post</a> on how to deploy with OpsWorks in general. For this tutorial you can take one of the following approaches:</p> <ul> <li> Take your existing stack from following along with that post, delete your database and MySQL layers, then follow this tutorial.</li> <li> Clone your existing stack (in case you don’t want to lose your work), create a new app server instance, delete the new stack’s MySQL layer, then follow along.</li> <li> Start from a brand new stack, and go between both tutorials, replacing the DB steps from the previous tutorial with the DB steps here. If you’re going to go that route, we would recommend reading this tutorial first to understand the differences in approach.</li> </ul> <p> Whichever approach you choose, you can be up and running in just a few minutes!</p> <h2> Create an RDS Instance</h2> <p> AWS OpsWorks will not create Amazon RDS instances on your behalf. You will need to create an instance and link it to OpsWorks.</p> <ol> <li> Open up the RDS console, navigate to <strong>Instances</strong>, and click <strong>Launch DB Instances</strong>.</li> <li> To be able to use our Rails example code unaltered, choose the MySQL engine (you can choose another engine if you like, see the next section for details).</li> <li> On the next screen, you can choose either Multi-AZ deployments or single-AZ, but if you want to stay within the <a href="http://aws.amazon.com/rds/free/">RDS Free Usage Tier</a>, then you should not choose a multi-AZ deployment.</li> <li> Make sure that you keep track of your <code>Master Username</code>, <code>Master Password</code>, and the <code>Database Name</code> from the rest of the form.</li> <li> Within <em>Configure Advanced Settings</em>, make sure you set your VPC Security Groups to include <code>AWS-OpsWorks-DB-Master-Server</code> and <code>AWS-OpsWorks-Rails-App-Server</code>. You can set <strong>Publicly Accessible</strong> to &quot;No&quot; as well.</li> <li> Once you’ve completed the forms, click <strong>Launch DB Instance</strong>. It may take a few minutes for your instance to launch, so now is not a bad time for tea or coffee.</li> </ol> <h3> Don’t Want MySQL?</h3> <p> You do not need to use MySQL as your database backend, that is just what we have chosen for this example. Want to use a different database backend? Just do the following:</p> <ol> <li> Replace the <code>mysql2</code> gem with the adapter gem appropriate to your DB engine selection.</li> <li> Make sure you also use your adapter selection in your custom deployment JSON, found in your stack settings if you used our exact tutorial steps.</li> <li> Of course, select that database engine when creating your RDS instance.</li> </ol> <h2> Create an RDS Layer</h2> <p> Now that you have an RDS Instance, you need to register it with OpsWorks.</p> <ol> <li> Navigate to the OpsWorks console, to the <strong>Layers</strong> section.</li> <li> Click <strong>+ Layer</strong>, and select the <strong>RDS</strong> tab.</li> <li> Your RDS instance should be on this screen to select. Select it, then enter your <strong>User</strong> and <strong>Password</strong> from the RDS instance creation step.</li> <li> Click <strong>Register with Stack</strong>.</li> </ol> <p> This registers your database with OpsWorks, and next you need to connect your app.</p> <h2> Attach Your RDS Instance to Your App</h2> <ol> <li> From the <strong>Apps</strong> section, click on <strong>Edit</strong> for TodoApp (or whatever app you are developing for).</li> <li> Under the <strong>Data Sources</strong> section, select <strong>RDS</strong>.</li> <li> It should auto-select your instance; select it if not. Then, fill in your <strong>Database name</strong> from the RDS instance creation process.</li> <li> Click <strong>Save</strong> to save your changes.</li> </ol> <p> Note that this should work for any of the topic branches we’ve made for TodoApp, as your choice of database host is transparent to your app so long as you have the correct database adapter gem in your <code>Gemfile</code>.</p> <h2> Deploy the App</h2> <p> To use your new database, simply run an app deployment, making sure you select the <strong>Migrate database</strong> option so that Rails can set up your database.</p> <p> Once that’s done, navigate to your app server host and play around with your app. You’re now running on RDS!</p> AWS re:Invent 2014 Ruby Recap https://aws.amazon.com/blogs/developer/aws-reinvent-2014-ruby-recap/ Tue, 02 Dec 2014 17:32:13 +0000 96f64c88a86e59060f22465d699b2f60fe81f936 Last week, we had a great time meeting with AWS customers using Ruby at AWS re:Invent! We appreciate the feedback we received, and the discussions that we had with you. AWS SDK for Ruby Presentation Notes At AWS re:Invent this year I took many of you on a tour of version 2 of the AWS […] <p> Last week, we had a great time meeting with AWS customers using Ruby at AWS re:Invent! We appreciate the feedback we received, and the discussions that we had with you.</p> <h2> AWS SDK for Ruby Presentation Notes</h2> <p> At AWS re:Invent this year I took many of you on a <a href="https://www.youtube.com/watch?v=9-PS5LtLZ9g">tour of version 2 of the AWS SDK for Ruby</a>. We were thrilled to have such a great audience, and we had a great time meeting with many of you both before and after the talk.</p> <p> In the presentation, we talked about the architecture and new features available in version 2 of the AWS SDK for Ruby, including resources, pagination, and waiters. We also walked through an end-to-end example using Ruby on Rails.</p> <p> If you didn’t get a chance to make it to my talk, I encourage you to check it out. If you did, you still might find it worthwhile to code along with our Rails example. You can <a href="https://www.youtube.com/watch?v=9-PS5LtLZ9g#t=1564">skip ahead to that here</a> if you like.</p> <p> The presentation also had a lot of links that you might want to check out. For your convenience, we’ve compiled them here:</p> <ul> <li> <a href="http://docs.aws.amazon.com/sdkforruby/api/frames.html">AWS SDK for Ruby V2 documentation</a></li> <li> <a href="https://github.com/aws/aws-sdk-core-ruby">AWS SDK for Ruby V2 on GitHub</a></li> <li> <a href="https://github.com/awslabs/todo-sample-app">&quot;TodoApp&quot; for Ruby on Rails</a></li> <li> <a href="http://ruby.awsblog.com/blog/tag/TodoApp">Blog series for Rails on AWS</a></li> <li> <a href="https://github.com/aws/aws-sdk-core-ruby/pull/127">Pull request for AWS CloudFormation Resources</a></li> <li> Finally, if you’re here, you’ve found our developer blog. Welcome!</li> </ul> <h2> See You Next Year</h2> <p> AWS re:Invent is October 6 – 9, 2015, once again at The Venetian in Las Vegas, NV. Let us know what you’d like to see next on <a href="https://twitter.com/awsforruby">Twitter @awsforruby</a> and we hope to see you there!</p> Client Response Stubs https://aws.amazon.com/blogs/developer/client-response-stubs/ Wed, 26 Nov 2014 19:04:20 +0000 79ad23b41a0e710338755358d728ed71e41314f1 We recently added client response stubs to the aws-sdk-core gem. Response stubbing disables network traffic and causes a client to return fake or stubbed data. # no API calls are made s3 = Aws::S3::Client.new(stub_responses: true) s3.list_buckets.buckets.map(&amp;:name) #=&gt; [] Custom Response Data By default, stubbed responses return empty lists, empty maps, and placeholder scalars. These empty […] <p> We <a>recently added</a> client response stubs to the <code>aws-sdk-core</code> gem. Response stubbing disables network traffic and causes a client to return fake or stubbed data.</p> <pre class="brush: ruby"> # no API calls are made s3 = Aws::S3::Client.new(stub_responses: true) s3.list_buckets.buckets.map(&amp;:name) #=&gt; []</pre> <h2> Custom Response Data</h2> <p> By default, stubbed responses return empty lists, empty maps, and placeholder scalars. These empty responses can be useful at times, but often you want to control the data returned.</p> <pre class="brush: ruby"> s3.stub_responses(:list_buckets, buckets:[{name:'aws-sdk'}]) s3.list_buckets.buckets.map(&amp;:name) #=&gt; ['aws-sdk']</pre> <h2> Safe Stubbing</h2> <p> One of the common risks when writing tests with stub data is that the stub doesn’t match the shape of the actual response. You risk coding against stubs that provide methods that won’t exist out of your tests.</p> <p> We resolve this issue by validating your stub data hash against the model of the API. An <code>ArgumentError</code> is raised when calling <code>#stub_responses</code> with invalid data.</p> <pre class="brush: ruby"> s3.stub_resposnes(:list_buckets, buckets:['aws-sdk']) #=&gt; raises ArgumentError, &quot;expected params[:buckets][0] to be a hash&quot;</pre> <h2> Stubbing Multiple Calls</h2> <p> By calling <a>#stub_responses</a> with an operation name and stub data, the client will serve that data for each call. You can specify multiple responses, and they will be used in sequence.</p> <pre class="brush: ruby"> s3.stub_responses(:list_buckets, { buckets:[{name:'aws-sdk'}] }, { buckets:[{name:'aws-sdk', 'aws-sdk-2'}] } ) s3.list_buckets.buckets.map(&amp;:name) #=&gt; ['aws-sdk'] s3.list_buckets.buckets.map(&amp;:name) #=&gt; ['aws-sdk', 'aws-sdk-2']</pre> <h2> Stubbing Errors</h2> <p> In addition to stubbing response data, you can configure errors to raise. You can specify a service error by name, or you can provide an error object or class to raise.</p> <pre class="brush: ruby"> # everything is broken s3.stub_responses(:head_bucket, 'NotFound' Timeout::Error, RuntimeError.new('oops') ) s3.head_bucket(bucket:'aws-sdk') # raises Aws::S3::Errors::NotFound s3.head_bucket(bucket:'aws-sdk') # raises a new Timeout::Error s3.head_bucket(bucket:'aws-sdk') # raises RuntimeError.new('oops')</pre> <p> You can mix stubbed response data and errors. This approach is great when you want to test how well your code recovers from errors.&nbsp;</p> <h2> Stubbing All Clients</h2> <p> The default config can be used to enable client stubbing globally. This can be very useful when writing tests to enable stubbing in your test helper once.</p> <pre class="brush: ruby"> # stub everything Aws.config[:stub_responses] = true</pre> <p> Give it a try and let us know what you think.</p> Waiters https://aws.amazon.com/blogs/developer/waiters/ Thu, 20 Nov 2014 19:04:22 +0000 a8391b9848ebdf19003d5e76ad72a8e62f32fffa We’ve added a feature called Waiters to the v2 AWS SDK for Ruby, and I am pretty excited about it. A waiter is a simple abstraction around the pattern of polling an AWS API until a desired state is reached. Basic Usage This simple example shows how to use waiters to block until a particular […] <p>We’ve added a feature called Waiters to the v2 AWS SDK for Ruby, and I am pretty excited about it. A waiter is a simple abstraction around the pattern of polling an AWS API until a desired state is reached.</p> <h2>Basic Usage</h2> <p>This simple example shows how to use waiters to block until a particular EC2 instance is running:</p> <pre class="brush: ruby">ec2 = Aws::EC2::Client.new ec2.wait_until(:instance_running, instance_ids:['i-12345678'])</pre> <p>Waiters will not wait indefinitely and can fail. Each waiter has a default polling interval and maximum number of attempts to make. If a waiter encounters an unexpected error or fails to reach the desired condition in time it will raise an error:</p> <pre class="brush: ruby">begin ec2.wait_until(:instance_running, instance_ids:['i-12345678']) resuce Aws::Waiters::Errors::WaiterFailed # oops end</pre> <h2>Configuration</h2> <p>You can modify the default interval and wait time between attempts by passing a block.</p> <pre class="brush: ruby"># this will wait upto ~ one hour ec2.wait_until(:instance_running, instance_ids:['i-12345678']) do |w| # seconds between each attempt w.interval = 15 # maximum number of polling attempts before giving up w.max_attempts = 240 end</pre> <h2>Callbacks</h2> <p>In addition to interval and maximum attempts, you can configure callbacks to trigger before each attempt polling attempt and before sleeping between attempts.</p> <pre class="brush: ruby">ec2.wait_until(:instance_running, instance_ids:['i-12345678']) do |w| w.before_attempt do |n| # n - the number of attempts made end w.before_wait do |n, resp| # n - the number of attempts made # resp -the client response from the previous attempt end end</pre> <p>You can throw <code>:success</code> or <code>:failure</code> from these callbacks to stop the waiter immediately. You can use this to write you own delay and back-off logic.</p> <p>Here I am using a callback to perform exponential back-off between polling attempts:</p> <pre class="brush: ruby">ec2.wait_until(:instance_running, instance_ids:['i-12345678']) do |w| w.interval = 0 # disable normal sleep w.before_wait do |n, resp| sleep(n ** 2) end end</pre> <p>This example gives up after one hour.</p> <pre class="brush: ruby">ec2.wait_until(:instance_running, instance_ids:['i-12345678']) do |w| one_hour_later = Time.now + 3600 w.before_wait do |n, resp| throw :failure, 'waited too long' if Time.now &gt; one_hour_later end end</pre> <h1>Waiters and Resources, Looking Ahead</h1> <p>You may have noticed that some waiters have already been exposed to the resource classes.</p> <pre class="brush: ruby">ec2 = Aws::EC2::Resource.new instance = ec2.instance('i-12345678') instance.stop instance.wait_until_stopped puts instance.id + ' is stopped'</pre> <p>In addition to connecting more waiters and resources, I’m excited to look into batch waiters. Imagine the following use case:</p> <pre class="brush: ruby">instances = ec2.create_instances(min_count: 5, ...) instances.wait_until_running puts &quot;the following new instances are now running:n&quot; puts instances.map(&amp;:id)</pre> <h1>Documentation</h1> <p>Waiters are documented in the Ruby SDK API reference. Each service client documents the <code>#wait_until</code> method and provides a list of available waiter names. Here are links to the <code>Aws::EC2::Client</code> waiter methods:</p> <ul> <li> <p><a href="http://docs.aws.amazon.com/sdkforruby/api/Aws/EC2/Client.html#wait_until-instance_method">Aws::EC2::Client#wait_until</a></p> </li> <li> <p><a href="http://docs.aws.amazon.com/sdkforruby/api/Aws/EC2/Client.html#waiter_names-instance_method">Aws::EC2::Client#waiter_names</a></p> </li> </ul> <p>Give waiters a try and let us know what you think!</p> Using Resources https://aws.amazon.com/blogs/developer/using-resources/ Tue, 18 Nov 2014 19:04:17 +0000 398d9ca563cfcd15d03d3ba58df8829625a901c0 With the recent 2.0 stable release of the aws-sdk-core gem, we started publishing preview releases of aws-sdk-resources. Until the preview status is released, you will need to use the –pre flag to install this gem: gem install aws-sdk-resources --pre In bundler, you should give the full version: # update the version as needed gem 'aws-sdk-resources', […] <p>With the recent 2.0 stable release of the <code>aws-sdk-core</code> gem, we started publishing preview releases of <code>aws-sdk-resources</code>. Until the preview status is released, you will need to use the –pre flag to install this gem:</p> <pre>gem install aws-sdk-resources --pre</pre> <p>In bundler, you should give the full version:</p> <pre class="brush: ruby"># update the version as needed gem 'aws-sdk-resources', version: '2.0.1.pre'</pre> <h2>Usage</h2> <p>Each service module has a <code>Client</code> class that provides a 1-to-1 mapping of the service API. Each service module now also has a <code>Resource</code> class that provides an object-oriented interface to work with.</p> <p>Each resource object wraps a service client.</p> <pre class="brush: ruby">s3 = Aws::S3::Resource.new s3.client #=&gt; #&lt;Aws::S3::Client&gt;</pre> <p>Given a service resource object you can start exploring related resources. Lets start with buckets in Amazon S3:</p> <pre># enumerate all of my buckets s3.buckets.map(&amp;:name) #=&gt; ['aws-sdk', ...] # get one bucket bucket = s3.buckets.first #=&gt; #&lt;Aws::S3::Bucket name=&quot;aws-sdk&quot;&gt;</pre> <p>If you know the name of a bucket, you can construct a bucket resource without making an API request.</p> <pre class="brush: ruby">bucket = s3.bucket('aws-sdk') # constructors are also available bucket = Aws::S3::Bucket.new('aws-sdk') bucket = Aws::S3::Bucket.new(name: 'aws-sdk')</pre> <p>In each of the three previous examples, an instance of <code>Aws::S3::Bucket</code> is returned. This is a lightweight reference to an actual bucket that <em>might exist</em> in Amazon S3. When you reference a resource, no API calls are made until you operate on the resource.</p> <p>Here I will use the bucket reference to delete the bucket.</p> <pre class="brush: ruby">bucket.delete</pre> <p>You can use a resource to reference other resources. In the next exmple, I use the bucket object to reference an object in the bucket by its key.<br /> Again, no API calls are made until I invoke an operation such as <code>#put</code> or <code>#delete</code>.</p> <pre class="brush: ruby">obj = bucket.object('hello.txt') obj.put(body:'Hello World!') obj.delete</pre> <h2>Resource Data</h2> <p>Resources have one or more identifiers, and data. To construct a resource, you only need the identifiers. A resource can load itself using its identifiers.</p> <p><strong>Constructing a resource object from its identifiers will never make an API call.</strong></p> <pre class="brush: ruby">obj = s3.bucket('aws-sdk').object('key') # no API call made # calling #data loads an object, returning a structure obj.data.etag #=&gt; &quot;ed076287532e86365e841e92bfc50d8c&quot; # same as obj.data.etag obj.etag #=&gt; &quot;ed076287532e86365e841e92bfc50d8c&quot;</pre> <p>Resources will never update internal data until you call <code>#reload</code>. Use <code>#reload</code> if you need to poll a resource attribute for a change.</p> <pre class="brush: ruby"># force the resource to refresh data, returning self obj.reload.last_updated_at</pre> <h2>Resource Associations</h2> <p>Most resources types are associated with one or more different resources. For example, an <code>Aws::S3::Bucket</code> object bucket has many objects, a website configuration, an ACL, etc.</p> <p>Each association is documented on the resource class. The API documentation will specify what API call is being made. If the association is plural, it will document when multiple calls are made.</p> <p>When working with plural associations, such as bucket that has many objects, resources are automatically paginated. This makes it simple to lazily enumerate all objects.</p> <pre class="brush: ruby">bucket = s3.bucket('aws-sdk') # enumerate **all** objects in a bucket, objects are fetched # in batches of 1K until every object has been yielded bucket.objects.each do |obj| puts &quot;#{obj.key} =&gt; #{obj.etag}&quot; end # filter objects with a prefix bucket.objects(prefix:'/tmp/').map(&amp;:key)</pre> <p>Some APIs support operating on resources in batches. When possible,<br /> the SDK will provide batch actions.</p> <pre class="brush: ruby"># gets and deletes objects in batches of 1K, sweet! bucket.objects(prefix:'/tmp/').delete</pre> <h2>Resource Waiters</h2> <p>Some resources have associated waiters. These allow you to poll until the resource enters a desired state.</p> <pre class="brush: ruby">instance = Aws::EC2::Instance.new('i-12345678') instance.stop instance.wait_until_stopped puts instance.id + ' is stopped'</pre> <h2>Whats Next?</h2> <p>The resource interface has a lot of unfinished features. Some of the things we are working on include:</p> <ul> <li>Adding <code>#exists?</code> methods to all resource objects</li> <li>Consistent tagging interfaces</li> <li>Batch waiters</li> <li>More service coverage with resource definitions</li> </ul> <p>We would love to hear your feedback. Resources are available now in the preview release of the <code>aws-sdk-resources</code> gem and in the master branch of GitHub.</p> <p>Happy coding!</p> Caching the Rails Asset Pipeline with Amazon CloudFront https://aws.amazon.com/blogs/developer/caching-the-rails-asset-pipeline-with-amazon-cloudfront/ Wed, 22 Oct 2014 12:04:19 +0000 40ee07be971b3aa73023e1af7b91783c9b3126d4 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 […] <p>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.</p> <p>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.</p> <p>With CloudFront’s support for custom origin servers, and features of the Rails asset pipeline, <a href="https://aws.amazon.com/cloudfront/">building a CDN</a> for your static assets is simple. In this blog post, we will show you how to set this up for your environment.</p> <h2>Do You Have Geographically Diverse Users?</h2> <p>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.</p> <p>* <a href="http://aws.amazon.com/cloudfront/details/">See the current list of edge locations here.</a></p> <h2>Prerequisites</h2> <p>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.</p> <h2>Creating a CloudFront Distribution</h2> <p>First, we will create a new CloudFront distribution that uses our app as the custom origin. From the <a href="https://console.aws.amazon.com/cloudfront/home">Amazon CloudFront console</a>, click <strong>Create Distribution</strong>. Under “Web”, click <strong>Get Started</strong>.</p> <p>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:</p> <ul> <li>If you have a domain name (e.g., “www.example.com”), then use that.</li> <li>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.</li> </ul> <p>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 <strong>Create Distribution</strong>.</p> <h2>Configuring the Ruby on Rails App to Use CloudFront</h2> <p>Using CloudFront as the asset Host for your static assets is truly a <a href="https://github.com/awslabs/todo-sample-app/commit/6e5ee4241f6a3618369b4ad0b026fc8eaa602c2f">one line change</a>.</p> <p>In <code>config/environments/production.rb</code>:</p> <pre class="brush:ruby">config.action_controller.asset_host = ENV['CLOUDFRONT_ENDPOINT'] </pre> <p>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.</p> <p>To pick up that change if you’re following along at home, go in to the OpsWorks console and edit your app:</p> <ul> <li>Under “Application Source”, point to the <code>cloudfront</code> branch.</li> <li>Add a new environment variable pair: <ul> <li>Key: CLOUDFRONT_ENDPOINT</li> <li>Value: The URL of your CloudFront endpoint, available in the CloudFront console. For e.g., “lettersandnumbers.cloudfront.net”</li> <li>You do not need to “Protect” this value.</li> </ul> </li> </ul> <p>Now, deploy your app! You do not need to run a database migration.</p> <h2>How It Works</h2> <p>While we wait for the deployment to complete, how does all of this work?</p> <p>If you look at the page source of our application before adding the CloudFront CDN, you’ll see lines like this:</p> <pre class="brush:html">&lt;link data-turbolinks-track=&quot;true&quot; href=&quot;/assets/application-0f3bf7fe135e88baa2cb9deb7a660251.css&quot; media=&quot;all&quot; rel=&quot;stylesheet&quot; /&gt; &lt;script data-turbolinks-track=&quot;true&quot; src=&quot;/assets/application-2ab5007aba477451ae5c38028892fd78.js&quot;&gt;&lt;/script&gt; </pre> <p>Those lines are how the page is including your <code>application.css</code> and <code>application.js</code> files. In <code>app/views/layouts/application.html.erb</code>, they correspond to these lines:</p> <pre class="brush:rails">&lt;%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' =&gt; true %&gt; &lt;%= javascript_include_tag 'application', 'data-turbolinks-track' =&gt; true %&gt; </pre> <p>In turn, these include statements source from <code>app/assets/stylesheets/application.css.scss</code> and <code>app/assets/javascripts/application.js</code>. If you run the command <code>rake assets:precompile</code>, these files will be compiled and a fingerprint will be added to the filename. For example, I ran <code>rake assets:precompile</code> and the following files were generated:</p> <ul> <li><code>public/assets/application-f3fd37796ac920546df412f68b0d9820.js</code></li> <li><code>public/assets/application-68a6279b040bd09341327b6c951d74bc.css</code></li> </ul> <p>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:</p> <pre class="brush:html">&lt;link data-turbolinks-track=&quot;true&quot; href=&quot;http://lettersandnumbers.cloudfront.net/assets/application-bfe54945dee8eb9f51b20d52b93aa177.css&quot; media=&quot;all&quot; rel=&quot;stylesheet&quot; /&gt; &lt;script data-turbolinks-track=&quot;true&quot; src=&quot;http://lettersandnumbers.cloudfront.net/assets/application-4984ddfbabfbae63ef17d0c8dca28d6c.js&quot;&gt;&lt;/script&gt; </pre> <p>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 <code>stylesheet_link_tag</code> and <code>javascript_include_tag</code> 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.</p> <p>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.</p> <h2>Wrap-Up</h2> <p>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.</p> <p>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!</p> Deploying Ruby on Rails Applications to AWS OpsWorks https://aws.amazon.com/blogs/developer/deploying-ruby-on-rails-applications-to-aws-opsworks/ Wed, 15 Oct 2014 13:06:29 +0000 efffc6da00aeb231036150d4cf89c0365721dccb 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 &quot;Todo Sample App&quot; to AWS using OpsWorks, with your […] <p> 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.</p> <p> Following along with this post, you should be able to deploy our &quot;Todo Sample App&quot; to AWS using OpsWorks, with your application and database running on different machine instances.</p> <h2> Getting Your Application Ready to Deploy</h2> <p> You can deploy the Todo sample application to OpsWorks directly from its public <a href="https://github.com/awslabs/todo-sample-app">GitHub repo</a>, using the ‘opsworks’ branch. If you explore the repo, you will notice that we’ve made a few design choices:</p> <ul> <li> Our secrets file at <code>config/secrets.yml</code> expects the <code>RAILS_SECRET_TOKEN</code> environment variable to be set on our application servers.</li> <li> We have required the <code>mysql2</code> gem, to interface with a MySQL database.</li> <li> We have required the <code>unicorn</code> gem, and will use unicorn as our app server.</li> </ul> <h2> Creating an OpsWorks Stack</h2> <p> Log in to the AWS Console and navigate to the <a href="https://console.aws.amazon.com/opsworks/home">AWS OpsWorks Console</a>. Click <code>Add Stack</code> and fill out the form like so:</p> <p> <img alt="Add Stack Screen" src="https://dmhnzl5mp9mj6.cloudfront.net/ruby_awsblog/images/opsworks-addstack.jpg" style="width: 760px;height: 439px" /></p> <p> Don’t worry about the &quot;Advanced&quot; settings for now – we won’t need them during this part of the tutorial. Once you’ve filled out the form, just press <code>Create Stack</code> and you’re done.</p> <h2> Creating the Rails App Server Layer</h2> <p> 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 <code>Add a layer</code>.</p> <p> <img alt="" src="https://dmhnzl5mp9mj6.cloudfront.net/ruby_awsblog/images/opsworks-addlayer.jpg" style="width: 760px;height: 394px" /></p> <p> We are making a few changes to the default options here. They are:</p> <ul> <li> Using Ruby version 2.1.</li> <li> Using &quot;nginx and Unicorn&quot; instead of &quot;Apache2 and Passenger&quot;.</li> <li> Using RubyGems version 2.2.1.</li> </ul> <p> Once you’re all done, click <code>Add Layer</code>. You’ll be redirected to the &quot;Layers&quot; screen.</p> <h2> Creating the Database Layer</h2> <p> Next, we’re going to create our database layer. On the layers screen, click <code>+ Layer</code>.</p> <p> <img alt="Add MySQL Layer" src="https://dmhnzl5mp9mj6.cloudfront.net/ruby_awsblog/images/opsworks-addlayer-mysql.jpg" style="width: 760px;height: 306px" /></p> <p> Choose &quot;MySQL&quot; 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!</p> <p> Click <code>Add Layer</code> and you’re done with this step.</p> <h3> MySQL Layer vs. Amazon RDS Layer</h3> <p> When creating your stack, you can choose to use an OpsWorks-managed EC2 instance running MySQL, called a &quot;MySQL&quot; layer, or you can create a layer that points to an existing Amazon RDS instance.</p> <p> 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.</p> <h2> Adding Instances</h2> <p> 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.</p> <h3> Create an App Server Instance</h3> <p> From the &quot;Layers&quot; screen, click <code>Add instance</code> in the &quot;Rails App Server&quot; layer.</p> <p> <img alt="Add Rails Instance" src="https://dmhnzl5mp9mj6.cloudfront.net/ruby_awsblog/images/opsworks-addinstance-rails.jpg" style="width: 760px;height: 508px" /></p> <p> We’re creating a <code>t2.micro</code> 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.</p> <p> Click <code>Add Instance</code> once you’re done, then <code>start</code> to begin the instance setup process. While that runs, we are going to make our database instance.</p> <p> One quick aside about using a <code>t2.micro</code> 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, <code>t2.micro</code> instances will not be available to you. Other instance types will, of course, work for this example.</p> <h3> Create a Database Instance</h3> <p> You’ll note that, if you’re following along with each step, you’re now at the &quot;Instances&quot; page. From either here or the layers page, under &quot;MySQL&quot;, click <code>Add an instance</code>.</p> <p> <img alt="Add MySQL Instance" src="https://dmhnzl5mp9mj6.cloudfront.net/ruby_awsblog/images/opsworks-addinstance-mysql.jpg" style="width: 760px;height: 521px" /></p> <p> As before, we are creating a <code>t2.micro</code> instance. Click <code>Add Instance</code> to create the instance, and <code>start</code> to begin instance setup.</p> <h2> Adding the Application</h2> <p> While our instances are set up, let’s add our application. Click the <code>Apps</code> link on the sidebar, then click <code>Add an app</code>.</p> <p> <img alt="Add App" src="https://dmhnzl5mp9mj6.cloudfront.net/ruby_awsblog/images/opsworks-addapp-1.jpg" style="width: 760px;height: 397px" /></p> <p> For this example, we’re using the Git repository at <code>https://github.com/awslabs/todo-sample-app.git</code> as our Application Source, and using the <code>opsworks</code> 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 &quot;TodoApp&quot; 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 &quot;TodoApp&quot;.</p> <p> <img alt="Add App" src="https://dmhnzl5mp9mj6.cloudfront.net/ruby_awsblog/images/opsworks-addapp-2.jpg" style="width: 760px;height: 449px" /></p> <p> To generate a value for the <code>RAILS_SECRET_KEY</code> environment variable, you can use the command <code>rake secret</code> within your copy of the repo. Just remember to set this as a &quot;Protected value&quot;, 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 <code>rake secret</code>.</p> <p> Click <code>Add App</code> when you are done.</p> <h2> Deploying the Application</h2> <p> 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.</p> <p> Click the <code>Deployments</code> link on the sidebar, then click the <code>Deploy an App</code> button.</p> <p> <img alt="Deploy App" src="https://dmhnzl5mp9mj6.cloudfront.net/ruby_awsblog/images/opsworks-deployapp.jpg" style="width: 760px;height: 512px" /></p> <p> Since we have not done so yet, remember to check &quot;Yes&quot; for the &quot;Migrate database&quot; setting. We will also need this custom JSON to ensure the &quot;mysql2&quot; adapter is used as intended:</p> <pre class="brush:javascript"> { &quot;deploy&quot;: { &quot;todoapp&quot;: { &quot;database&quot;: { &quot;adapter&quot;: &quot;mysql2&quot; } } } } </pre> <p> Click <code>Deploy</code>, and grab another cup of tea. You’ve now deployed the Ruby on Rails &quot;Todo&quot; sample app to AWS OpsWorks!</p> <h3> Use Custom JSON for All Deployments</h3> <p> 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.</p> <p> Click the <code>Stack</code> link on the sidebar, open <code>Stack Settings</code>, and click <code>Edit</code>.</p> <p> <img alt="Stack Settings" src="https://dmhnzl5mp9mj6.cloudfront.net/ruby_awsblog/images/opsworks-stacksettings.jpg" style="width: 760px;height: 501px" /></p> <p> Add the custom JSON you used for your deployment earlier, and click <code>Save</code>.</p> <h2> Try It Out</h2> <p> 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 &quot;Public DNS&quot;, and you should see the front page of the application:</p> <p> <img alt="" src="https://dmhnzl5mp9mj6.cloudfront.net/ruby_awsblog/images/opsworks-todoapp-index.jpg" style="width: 760px;height: 85px" /></p> <p> You can add tasks, mark them complete, and delete them as you like. In short, your application is running and performing database transactions.</p> <p> <img alt="Hello TodoApp!" src="https://dmhnzl5mp9mj6.cloudfront.net/ruby_awsblog/images/opsworks-todoapp-hello.jpg" style="width: 760px;height: 208px" /></p> <h2> Wrap-Up</h2> <p> 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.</p> <p> 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.</p> <p> 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!</p> Blog Series: Ruby on Rails on Amazon Web Services https://aws.amazon.com/blogs/developer/blog-series-ruby-on-rails-on-amazon-web-services/ Mon, 13 Oct 2014 19:17:35 +0000 c551beb7332a4c196457d559c3c29cb5a9061335 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 […] <p> 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.</p> <h2> The Sample App</h2> <p> For this blog series, we have built a sample app in Ruby on Rails. You can find it on GitHub as <a href="https://github.com/awslabs/todo-sample-app">awslabs/todo-sample-app</a>.</p> <p> 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.</p> <p> 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.</p> <h2> What the Series Will Cover</h2> <p> 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.</p> <p> Have a topic you’d love for us to cover? Let us know in the comments!</p> <h2> Up Next</h2> <p> The first post, showing you how to deploy the Todo Sample App to AWS OpsWorks will be out soon. Stay tuned!</p>