link_to是Rails中提供的一個內置方法,用于產生一個超鏈接,常用的方法通常是link_to "鏈接文字", options = {}, html_options = {}, 如果我們不指定提交的方法,默認情況下將產生一個HTTP GET請求,但是我們也可以通過指定提交方法來避免某些敏感數據的泄漏。
在《Agile web development with Rails》一書中,有這樣一個練習題:為購物網站上面的圖片添加一個超鏈接,當點擊該圖片時請求名為store的controller下add_to_cart action,同時要求使用POST方式來請求。代碼如下所示:
<%= link_to image_tag(product.image_url), options = {:action => "add_to_cart"}, html_options={:method => "post"} %>
其中第一個參數image_tag是一個內置方法,用于產生一個<img src="xxx" />的HTML標簽,而options接受一個hash容器,在這個容器中只有一個參數action,它告訴了請求對應的action,于是rails會在構建<a>表情的href屬性時將其轉換為:http:localhost:3000/store/add_to_cart 這種形式:即請求StoreController下的add_to_cart方法。最重要的一定是html_options參數,它也接受一個hash容器,通過method="post"來告訴瀏覽器,采用post方式來提交請求。
但是我們知道post通常是在form中才用到的,這里并沒有form的定義,那么是如何采用post方式來進行提交的呢?通過閱讀瀏覽器解析后的源代碼,我們可以發現rails在編譯期間做了很巧妙的處理:它創建了一個動態的、隱藏的表單來提交:
<a href="/store/add_to_cart" onclick="..."><img alt="Auto" src="/images/auto.jpg?1265130093" /></a>

下面就是onClick的內容:


{
//創建一個隱式的表單對象,并設置提交方式為POST,已經設置提交的URL
var f = document.createElement('form');
f.style.display = 'none';
this.parentNode.appendChild(f);
f.method = 'POST';
f.action = this.href;

//為表單添加一個隱藏域,指定提交的方式參數
var m = document.createElement('input');
m.setAttribute('type', 'hidden');
m.setAttribute('name', '_method');
m.setAttribute('value', 'post');
f.appendChild(m);
//為表單添加一個隱藏域,指定當前的Session token key,防止重復提交
var s = document.createElement('input');
s.setAttribute('type', 'hidden');
s.setAttribute('name', 'authenticity_token');
s.setAttribute('value', '6c02dccc61c8e299bf1765bd0414355e9d8a4815');
f.appendChild(s);
//動態提交表單
f.submit();
return false;"
}
這就是采用post方式提交請求的“秘密”,rails的實現相當優雅!可是如果我們把上面的link_to代碼稍微改一下,如下面所示,會有什么結果呢?
<%= link_to image_tag(product.image_url), {:action => "add_to_cart", :method => "post"} %>
我們來看看最終產生的頁面源代碼
<a href="/store/add_to_cart?method=post"><img alt="Auto" src="/images/auto.jpg?1265130093" /></a>
很明顯,method=post變成了URL的請求參數,而不是HTTP 請求報頭了。也就是說這里產生的是一個HTTP GET請求:http://localhost:3000/store/add_to_cart?method=post,而正確的請求應該是:http://localhost:3000/store/add_to_cart
所以我們一定要記住:options={}是用來傳遞請求參數的,而html_options={}是用來設置請求報頭的,不能搞混!
-------------------------------------------------------------
生活就像打牌,不是要抓一手好牌,而是要盡力打好一手爛牌。
posted on 2010-05-17 16:41
Paul Lin 閱讀(6502)
評論(4) 編輯 收藏 所屬分類:
RoR