「RailsによるアジャイルWebアプリケーション開発」21章読み中
ActionControllerの続き。
コントローラクラス内のpublicメソッドをactionとして使わない方法。
通常であれば、privateメソッド、もしくは、protectedメソッドとして隠します。
private # DELETE /products/1 # DELETE /products/1.xml def destroy @product = Product.find(params[:id]) @product.destroy respond_to do |format| format.html { redirect_to(products_url) } format.xml { head :ok } end end
この状態で、destoryアクションを呼ぶと、Unknown action (No action responded to destory)となります。
じゃあ、publicのままで、でも、アクションとして使いたくない場合は、hide_actionを使います。
hide_action :destroy # DELETE /products/1 # DELETE /products/1.xml def destroy @product = Product.find(params[:id]) @product.destroy respond_to do |format| format.html { redirect_to(products_url) } format.xml { head :ok } end end
同じく、Unknown actionとなります。
ただ、本書中にもあるように、コントローラ中にアクションでないpublicメソッドがある場合は、リファクタリングを検討した方が良さそうです。
Unknown actionが発生した時にデバッグ情報を出力する
render(:inline => string, [:type => "rhtml"|"rxml"|"rjs"], [:locals => hash])
を使うとできます。
if RAILS_ENV == "development" def method_missing(name, *args) render(:inline => %{ <h2>Invalid Action: #{name}</h2> request parameter is :<br/> <%= debug(params) %> }) end end
if RAILS_ENV == "development"は、開発モードのみという判定。
上記のコードをコントローラ(products_controller.rb)の一番下に入れて、
試しにhttp://localhost:3000/products/hoge/1にアクセスしてみると、以下のように表示されました。
Invalid Action: hoge request parameter is : --- !map:HashWithIndifferentAccess action: hoge id: "1" controller: products
デバッグに役立ちそうですね。
ファイルをダウンロード
send_dataとか、send_fileというのを使うらしい。
試しに、products_controller.rbに以下のようなメソッドを追加。
def index_download @products = Product.find(:all) send_data(@products, :filename => "products.txt") end
で、
http://localhost:3000/products/index_download/1
にアクセス。
すると、
おお!出た出た。
割りと簡単なのね。
で、早速ダウンロードしたファイルを開いてみる。
#<Product:0xb7798cb0>
...全く面白くないが、ダウンロードさせるっていう目的はいいみたい。
つまらないので、CSV形式(タイトル,URL)にしてみる。
products_controller.rbを以下のように修正。
def index_download @products = Product.find(:all) data = "" @products.each { |p| data = data + p.title + "," + p.image_url data = data + "\n" } send_data(data, :filename => "products.txt") end
別にどうってことはないのですが、ちょっとは実用的になったかも。
URLはちょっとヘンですが。。
(2008/07/24 追記)
routes.rbに以下の行を追加。
map.connect ':controller/index_download', :action => "index_download"
map.resources :products
の行の前に入れないとダメです。
これで、
http://localhost:3000/products/index_download
と、/1なしのURLでもindexをダウンロードすることが出来るようになりました。
301 Moved Permanentlyを返す(つもりが出来てない?)
products_controller.rbにこんなアクションを追加。
def moved headers["Status"] = "301 Moved Permanently" redirect_to("http://www.yahoo.co.jp/") end
で、
http://localhost:3000/products/moved/1
にアクセス。
すると、Yahoo Japanのホームページに飛びました。
一見うまくいったように見えるものの、Live HTTP Headersで見てみると、
なぜか
HTTP/1.x 302 Found
が返ってきてる。なんでだろ。
Rails的に301よりも302の方が適切っていう判断なのかしら。
(2008/07/24 追記)
コメント欄で指摘いただきましたが、
def moved # headers["Status"] = "301 Moved Permanently" redirect_to("http://www.yahoo.co.jp/", :status => 301) end
でうまくいきました。