[Rails][Amazon] Ruby on Rails で Amazon ショッピングカートを作成する カート編
移転しました。
5.カート画面
機能
・カートの商品数変更 (再計算ボタン押下)
・カートの商品削除 (削除リンク押下)
・Amazon購入画面へ遷移 (購入手続きへ進むボタン押下)
制限事項
・商品数量の入力チェックは行わない
・リロードの対応は行わない
amazon_ecs 0.5.3のソース 修正。
amazon_ecs 0.5.3のソースそのままではカート操作ができない。
このため、amazon_ecsを拡張したモジュールを追加する。
・拡張モジュール lib/amazon/ecsex.rb
# Amazon ECS 0.5.3 にはカートを操作するメソッドが無いため自作 module Ecsex class RequestError < StandardError; end # カートを作成し、カートIDと、HMACを保持したHASHを返却する def self.item_createCart(asin, quantity) opts = {} opts[:operation] = 'CartCreate' opts['Item.1.ASIN'] = asin opts['Item.1.Quantity'] = quantity Amazon::Ecs.send_request(opts) end # カートをクリア def self.item_clearCart(cart) opts = {} opts[:operation] = 'CartClear' opts['CartId'] = cart['cartid'] opts['HMAC'] = cart['urlencodedhmac'] Amazon::Ecs.send_request(opts) end # 数量1のカートを作成 def self.item_createCart_single(asin) item_createCart(asin, 1) end # カートに商品を追加する def self.item_addCart(asin, cart) opts = {} opts[:operation] = 'CartAdd' opts['CartId'] = cart['cartid'] opts['HMAC'] = cart['urlencodedhmac'] opts['Item.1.ASIN'] = asin opts['Item.1.Quantity'] = 1 Amazon::Ecs.send_request(opts) end # カート内容を参照 def self.item_refCart(cart) opts = {} opts[:operation] = 'CartGet' opts['CartId'] = cart['cartid'] opts['HMAC'] = cart['urlencodedhmac'] Amazon::Ecs.send_request(opts) end # カートの商品を変更する def self.item_modCart(itemList, cart) opts = {} opts[:operation] = 'CartModify' opts['CartId'] = cart['cartid'] opts['HMAC'] = cart['urlencodedhmac'] cnt = 1 itemList.each do |item| opts['Item.' + cnt.to_s + '.CartItemId'] = item['cartitemid'] opts['Item.' + cnt.to_s + '.Quantity'] = item['quantity'] cnt += 1 end Amazon::Ecs.send_request(opts) end end
さらに、amazon_ecs 0.5.3 をそのまま使用するとAmazonとやり取りするHMACが勝手にURLエンコードされてしまい、サーバー側で保持しているHMACの値と異なってカート処理が行えない場合がある。
このためもともとのソース(RUBY_HOME\lib\ruby\gems\1.8\gems\amazon-ecs-0.5.3\lib\amazon)を以下のように修正し、libディレクトリ(lib/amazon/ecs.rb)に配備する。
・修正前
def self.prepare_url(opts) country = opts.delete(:country) country = (country.nil?) ? 'us' : country request_url = SERVICE_URLS[country.to_sym] raise Amazon::RequestError, "Invalid country '#{country}'" unless request_url qs = '' opts.each {|k,v| next unless v v = v.join(',') if v.is_a? Array qs << "&#{camelize(k.to_s)}=#{URI.encode(v.to_s)}" } "#{request_url}#{qs}" end
・修正後
def self.prepare_url(opts) country = opts.delete(:country) country = (country.nil?) ? 'us' : country request_url = SERVICE_URLS[country.to_sym] raise Amazon::RequestError, "Invalid country '#{country}'" unless request_url qs = '' kind = opts[:operation][0..3] # ADD opts.each {|k,v| next unless v v = v.join(',') if v.is_a? Array if kind == 'Cart' # ADD qs << "&#{camelize(k.to_s)}=#{v.to_s}" # ADD else # ADD qs << "&#{camelize(k.to_s)}=#{URI.encode(v.to_s)}" end # ADD } "#{request_url}#{qs}" end
HTML
・app/views/amazon_ecs/cart.rhtml
<h1>Amazon カート画面</h1> <table> <% if @items.length != 0 %> <%= form_tag :action => 'cart', :operate => 'mod' %> <tr> <td>1. ショッピングカートの中身を確認。</td> </tr> <tr> <td> <table> <tr bgcolor="#CA9947"> <th width="90" nowrap="nowrap" height="25" align="center"> 商品コード </th> <th width="410" align="center"> 商品名 </th> <th width="70" nowrap="nowrap" align="center"> 単価 (税込) </th> <th width="50" nowrap="nowrap" align="center"> 数量 </th> <th width="70" nowrap="nowrap" align="center"> 小計 (税込) </th> <th width="70" nowrap="nowrap" align="center"> 削除 </th> </tr> <!-- 繰り返し --> <% count = 1 %> <% @items.each do |item| -%> <tr> <td bgcolor="#F0F0F0" nowrap="nowrap" align="center"> <%=h item['asin'] %> </td> <td bgcolor="#F0F0F0"> <%= item['title'] %> </td> <td bgcolor="#F0F0F0" align="right"> <%=h item['price'] %> </td> <td bgcolor="#F0F0F0" nowrap="nowrap" align="center"> <%= text_field_tag('quantity' + count.to_s, item['quantity'], :size => '2', :maxlength => '3') %> </td> <td bgcolor="#F0F0F0" nowrap="nowrap" align="right"> <%= number_to_currency( item['totalprice'],:unit => "\",:precision => 0 ) %> </td> <td align="center" bgcolor="#F0F0F0" nowrap="nowrap"> <%= hidden_field_tag 'cartitemid' + count.to_s, item['cartitemid'] %> <%=link_to('削除', 'http://localhost:3000/amazon_ecs/cart?operate=del&cartitemid=' + item['cartitemid']) %> </td> </tr> <% count += 1 %> <% end -%> <!-- //繰り返し --> <tr> <td height="5" colspan="6"> <%=image_tag('spacer.gif', :width => 1, :height => 1) %> </td> </tr> <tr> <td> <%=image_tag('spacer.gif', :width => 1, :height => 1) %> </td> <td nowrap="nowrap" align="right" colspan="3"> 合計金額 (税込) </td> <td colspan="2" bgcolor="#CA9947" nowrap="nowrap" align="right"> <%=h @totalPrice %> </td> </tr> </table> </td> </tr> <tr> <td><%=image_tag('spacer.gif', :width => 1, :height => 15) %></td> </tr> <tr> <td valign="top">2. 数量を変更した場合は、「再計算」をクリック。</td> </tr> <tr> <td height="50"> <p align="center"> <%= hidden_field_tag 'cartitemnum', @items.size %> <%=submit_tag('再計算') %> </p> </td> </tr> <%= end_form_tag %> <%= form_tag :action => 'cart', :operate => 'buy' %> <tr> <td><%=image_tag('spacer.gif', :width => 1, :height => 15) %></td> </tr> <tr> <td>3. 「購入手続きへ進む」をクリックでAmazonの購入手続き画面へ。</td> </tr> <tr> <td height="70"> <table border="0" cellpadding="5" cellspacing="0" width="375" align="center"> <tr> <td valign="top" width="235" align="left"> <%=submit_tag('購入手続きへ進む') %> </td> </tr> </table> </td> </tr> <%= end_form_tag %> <tr> <td height="50"> <%=image_tag('spacer.gif', :width => 1, :height => 1) %> </td> </tr> <% else %> <tr> <td> ショッピングカートに商品は入っていません。 </td> </tr> <% end %> </table> </div>
Controller
・app/controller/amazon_ecs_controller.rb
class AmazonEcsController < ApplicationController require 'amazon/ecs' require 'amazon/ecsex' # 追加 : : # カート画面表示 def cart @errmsg = params[:errmsg] # カート内容が存在しない場合は、カートを作成し終了 if session[:cart] == nil || session[:cart]['cartid'] == '' || session[:cart]['cartid'] == nil @items = createCart # カート作成 # 商品追加 elsif params[:operate] == 'add' @items = addCart # カート内容参照 elsif params[:operate] == 'ref' @items = refCart # カート内容変更 elsif params[:operate] == 'mod' @items = modCart # 商品削除 elsif params[:operate] == 'del' @items = delCart # 商品購入 elsif params[:operate] == 'buy' buyItem end end # 商品購入処理 def buyItem # 遷移するAmazon側URLを取得 doc = Ecsex.item_refCart(session[:cart]).doc # Amazon へリダイレクト redirect_to (doc/"purchaseurl").inner_html end # カートの商品削除 def delCart # asid と quantityのHashをリストにして渡す paramList = [] ary = ['cartitemid', params['cartitemid'], 'quantity', 0] paramList.push(Hash[*ary]) doc = Ecsex.item_modCart(paramList, session[:cart]).doc # 表示オブジェクト作成 getShowObject4Cart(doc) end # カート内容参照 def refCart doc = Ecsex.item_refCart(session[:cart]).doc # 表示オブジェクト作成 getShowObject4Cart(doc) end # カートに商品を変更する def modCart # asid と quantityのHashをリストにして渡す max = params[:cartitemnum].to_i paramList = [] for i in 1..max ary = ['cartitemid', params['cartitemid' + i.to_s], 'quantity', params['quantity' + i.to_s]] paramList.push(Hash[*ary]) end doc = Ecsex.item_modCart(paramList, session[:cart]).doc # 表示オブジェクト作成 getShowObject4Cart(doc) end # カートに商品追加 def addCart doc = Ecsex.item_addCart(params[:asin],session[:cart]).doc # 表示オブジェクト作成 getShowObject4Cart(doc) end # カート作成 def createCart doc = Ecsex.item_createCart_single(params[:asin]).doc ary = ['cartid', (doc/'cartid').inner_html, 'urlencodedhmac', (doc/'urlencodedhmac').inner_html] session[:cart] = Hash[*ary] # 表示オブジェクト作成 getShowObject4Cart(doc) end # カート表示オブジェクトの取得 def getShowObject4Cart(doc) carts = (doc/"cartitems/cartitem").collect {|item| Amazon::Element.new(item)} rtnList = [] carts.each do |cart| ary = ['asin', cart.get('asin'), 'title', cart.get('title'), 'price', cart.get('price/formattedprice'), 'quantity', cart.get('quantity'), 'totalprice', cart.get('price/amount').to_i * cart.get('quantity').to_i, 'cartitemid', cart.get('cartitemid') ] rtnList.push(Hash[*ary]) end prices = (doc/'subtotal').collect {|item| Amazon::Element.new(item)} prices.each do |price| @totalPrice = price.get('formattedprice') end rtnList end end