RailsでAmazonの商品を扱う
Amazonの商品はAPIを介して簡単に取得できますが, 取得した情報はキャッシュ目的以外でローカルに格納してはいけない, などの制約がある. なのでどんな風に書けばいいかメモ. あと毎回APIを介していては遅くなるのでmemcachedを使う(キャッシュ目的なのでOKなはず).
まずAmazonのAPIに簡潔にアクセスできるRubyGemsを入れる.
$ sudo gem install amazon-ecs
次にRailsのconfigの中身を書き換えておく.
# config/environment.rb config.gem 'amazon-ecs', :lib => 'amazon/ecs'
# config/initializers/amazon_ecs.rb Amazon::Ecs.options = { :aWS_access_key_id => 'APIを使うために必要なアクセスキー', :country => :jp, :response_group => 'Medium' }
そしてマイグレーションファイル.
class CreateAmazonItems < ActiveRecord::Migration def self.up create_table :amazon_items do |t| t.string :asin, :null => false t.timestamps end end def self.down drop_table :amazon_items end end
ASINのみは恒久的に保持しておいていいのでこうする(他のを含めると規約違反なはず).
後はモデル.
class AmazonItem < ActiveRecord::Base validates_presence_of :asin def get(path) lookup unless @looked @item && @item.get(path) end protected def validate lookup unless @looked errors.add :asin, "can't find the item from Amazon" unless @item end private def lookup @item = Amazon::Ecs.item_lookup(asin).first_item @looked = true end end
必要なときだけlookupメソッドでAmazonに要求するようにし, 2回目以降は当然リクエストしないようにしておく.
コレで:
amazon_item = AmazonItem.find_by_asin '4797336617' puts amazon_item.get 'itemattributes/title' # => たのしいRuby 第2版 Rubyではじめる気軽なプログラミング
こんな感じに取得できる.
だけどASINが同一でも, インスタンスが違えば@lookedインスタンス変数は偽となる(nil)なので, そういう場合はやっぱり速度が落ちる. というコトでキャッシュを導入.
$ sudo port install memcached $ sudo gem install memcache-client
class AmazonItem < ActiveRecord::Base CACHE_SERVERS = 'localhost:11211' validates_presence_of :asin def get(path) lookup unless @looked @item && @item.get(path) end protected def validate lookup unless @looked errors.add :asin, "can't find the item from Amazon" unless @item end private def lookup unless @@cache require 'memcache' # Amazon::Ecsはrequire 'amazon/ecs'しなくても使える(それはそれで怪しい)が…… @@cache = MemCache.new CACHE_SERVERS end if @item = @@cache[asin] @item = Amazon::Element.new Hpricot @item elsif @item = Amazon::Ecs.item_lookup(asin).first_item @@cache.add asin, @item.to_s, 24 * 60 * 60 end @looked = true end end
あとconfig/environment.rbにも追記する.
config.gem 'memcache-client', :lib => 'memcache'
コレだけで劇的に早くなった. 発想は単純だけど, 単純だからこそなのか, キャッシュはかなり効果的だなぁ. あとAPIを介して取得した情報はキャッシュしてもいいが, 1日だけという期限がついている. それもmemcachedを使えば, うまい具合にできてしまう. コレはいいや.