INCLUDE_DATA

Article written

  • on 18.07.2005
  • at 06:45 PM
  • by Rory

Amazon Web Services on Rails 9

Jul18

If you’re looking to make use of the Amazon Web Services through your Rails app, here’s a tip: avoid trying to communicate with them using the Ruby on Rails ActiveWebServices classes. I spent a couple hours trying to patch together a solution, but nothing would work. I believe what currently exists is geared towards making your Rails app accessible through Soap or XMLRPC, rather than consuming exisiting web services.

Instead, use Ruby/Amazon, a “Ruby language library that allows programmatic access to the popular Amazon Web site via the REST (XML over HTTP) based Amazon Web Services.” Installation of the library on my development box was a breeze (just read the installation document to learn how) and, plus, it’s already preinstalled on the servers at TextDrive, so getting going using the Ruby/Amazon library is not a problem at all. For a quick tutorial on how to use the library, check out the documentation on the top-level Amazon module or read this entry on the GleepGlop blog. Both contain examples that show you how to make a basic connection to Amazon through the web services and how to query for products.

Once you get this far, though, you’ll realize that making calls to the Amazon Web Services with every page view is going to decrease the speed at which your website will render for your users. So what can you do instead? Cache the results in your database, that’s what. On my lyrics website, I want to have links back to Amazon for every artist that I have lyrics for. So, what I did was create an administrative function that will connect to Amazon and return a list of items for a given artist. This process is repeated over and over so that I have a huge archive of products for each of the artists. Then, instead of querying Amazon with each page view, I just need to call this administrative function every month or so, to update the products in my database.

Below, you’ll see a body of code that updates all products for all artists whose names begin with a particular letter (for example, “A”). For each artist, all existing products are deleted from the database. Then, a new list of products is retrieved and each product is added to the database.

amazon_controller.rb
require 'amazon/search'

class AmazonController < AdminController
   include Amazon::Search

   ASSOCIATES_ID = "amazonaffiliateid-20" # Your Amazon Affiliate ID
   DEV_TOKEN = "0222NLPJQD0A7633Q182" # Your Amazon Web Services Key

   def update
      artists = Artist.find_by_first_letter(@params["letter"])

      artists.each do |artist|
         # Delete all existing "out-dated" products
         existing_products = Product.find_all_by_artist_id(artist.id)
         existing_products.each do |existing_product|
            existing_product.destroy
         end

         # Query Amazon
         request = Request.new(DEV_TOKEN, ASSOCIATES_ID)
         response = request.artist_search(artist.artist_name)
         products = response.products

         # Loop over each product and add them to the database, one at a time
         products.each do |product|
            new_product = Product.new

            new_product.artist_id = artist.id
            new_product.product_name = product.product_name
            new_product.url = product.url
            new_product.image_url_small = product.image_url_small
            new_product.image_url_medium = product.image_url_medium
            new_product.image_url_large= product.image_url_large

            new_product.save
            new_product = nil
         end
      end

      redirect_to(:controller =< "admin", :action => "index") # Return to the list page if it suceeds
   end
end

What I’d like to do now is to have a Ruby script run nightly that updates a portion of the products in the database. For example, at midnight on the first day of each month, all artists whose names begin with A would have their products updated from Amazon. At midnight on day two, all B artists would have their products updated. I just have to figure out how to do this… but once I do, I’ll post it here.

subscribe to comments RSS

There are 9 comments for this post

  1. Peat Bakke says:

    I can vouch for the simplicity of building an Amazon “portal” using Rails. I built Peat’s Books (http://www.peatsbooks.com/) from scratch (without the ruby/amazon package) in my spare time over a few days. It’s pretty straight forward to use net/http for making REST queries, and REXML (http://www.germane-software.com/software/rexml/) to parse Amazon’s responses. Building an Amazon site is a pretty friendly bootcamp for learning about web services. :)

  2. Rory, have you had any problems running this code on Rails 1.0?

    I’m trying to use Ruby/Amazon to add some information to a product database and run into lots of either “is not a module” or “uninitialized constant Search” type errors.

    Things run ok from the command line so I’m trying to figure out if there is a trick with 1.0?
    Thank you,
    iolaire

  3. [...] Rory on Rails » Amazon Web Services on Rails (tags: amazon WebServices RubyOnRails ruby rails) [...]

  4. Ruby/Amazon says:

    [...] Ruby/Amazon ist eine Ruby Bibliothek für den Zugriff auf die Webservices von Amazon via REST (XML über HTTP). Die Dokumentation der Bibliothek kommt über RDoc und findet sich hier. Eine etwas ausführlichere Beschreibung inklusive Beispiel hat Rory. [...]

  5. One example that I had intially intended to get into the PDF I published through O’Reilly (Web Services with Rails) was a client for the Alexa Page rank service…it didn’t really fit into any of the specific areas I ended up covering, so I’m just going to dump out the code here for anyone that’s interested (email me if you have questions/comments – kevinm at rorbe.com ):

    # we use two libraries for this example
    require ‘hmac-sha1′
    require ’soap/rpc/driver’

    # set up some default variables
    url = “draftwizard.com”
    responsegroup = “Rank”
    temp = Time.now.utc

    # get the time into the format for creating our signature
    t1 = temp.strftime(”%Y-%m-%dT%H:%M:%SZ”)

    newtime = t1.to_s

    encval = “AlexaWebInfoServiceUrlInfo” + t1.to_s

    # now actually create our signature (based on rules supplied in AWS documentation)
    myhmac = HMAC::SHA1.digest(”YOUR AMAZON/ALEXA KEY TO GENERATE SIGNATURE”, encval)

    # it needs to be binary, and for some reason the packing was addining one extra character; hence the chomp
    myhmac = myhmac.to_a.pack(”m”).chomp

    # now we can set up our driver
    driver = SOAP::RPC:: Driver.new(”awis.amazonaws.com/onca/soap?Service=AlexaWebInfoService”,”webservices.amazon.com/AWSAlexa/2005-07-11″)

    driver.add_rpc_method_with_soapaction_as(”test”, “UrlInfo”, “UrlInfo”, “AWSAccessKeyId”, “Signature”, “Timestamp”, “Url”, “ResponseGroup”)

    # and finally we can make ou real request for the data
    result = driver.test(”YOUR ALEXA KEY”, myhmac, newtime, url, responsegroup)

    # and display the results.
    puts result[1]["Alexa"]["TrafficData"]["Rank"]

    The driver = line above has a space after the RCP colons (and before the word Driver)…that’s because the colon D on this msg. board renders as a smiley…so I added the space so the image wouldn’t render…but in your actual code, you can not have the space there. Just a head’s up.

  6. [...] First I needed a way to communicate with Amazon Web Service. After some searching I found that you could use ActionWebService to do that, but too many people said that this was way too complicated and suggested using Ruby/Amazon library instead. [...]

  7. [...] Rory Hansen » Amazon Web Services on Rails (tags: amazon howto rails rubyonrails webservice) [...]

  8. Kevin says:

    Any thoughts/tutorial on how to display the results in a Rails application? I am new to both Ruby and Rails. Also posted this question on http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/41c84b0616d161a1

  9. roupen nahabedian says:

    Thanks for the post … i see that its been a while since the original . Did you figure out how the the midnight runs? You promised to post here ;-)

Please, feel free to post your own comment

* these are required fields