Rails 3 提供了match
方法供我們自定義routes,然而我們要小心使用它以避免“跨站腳本攻擊”(XSS Attack)。比如像這樣的 routes:
注:(r3 代表Rails 3,r4 代表Rails 4)
# routes.rb
match '/books/:id/purchase', to: 'books@purchase'
用戶可以很輕鬆地使用XSS Attack CSRF Attack,比如使用這樣一個鏈接:
CodeSchool 的Rail 4 教程裡寫的是XSS Attack,經查證和問詢,證明這是CodeSchool 的失誤,應該會很快改正過來,再次先做一個修正,並向受到誤導的朋友致歉
<a href="http://yoursite.com/books/4/purchase">Get It Free!</a>
這會使用GET 去請求這個資源,你絕對不想看到這種情況(你希望的是POST),所以你要限制客戶端可以訪問此資源的方式。例如:
match '/books/:id?purchase', to: 'books@purchase', via: :post # :all 代表匹配所有的HTTP methods
# 或者
post '/books/:id?purchase', to: 'books@purchase'
否則你就會收到如下錯誤提示:
You should not use the
match
method in your router without specifying an HTTP method. (RuntimeError)
過去我們使用put
來完成對資源的更新請求,然而put
本身是對整個資源(數據集合)進行更新,若要實現部分資源的更新(單個數據,或是幾個產生變化的數據實體),put
就有點過重了,此時patch
會更加合適。
patch
並不是什麼新東西,此前就一直存在於HTTP 1.1 協議規範之中,只不過這一次Rails 4 把它正式的引入進來。在Rails 4 中,put
和patch
都指向controller#update
,在更新部分資源時(比如@book)會使用patch
,生成類似下例中的頁面元素:
<form action="/books/20" method="post">
<div style="margin:0;padding:0;display:inline">
<input name="utf8" type="hidden" value="✓" />
<input name="_method" type="hidden" value="patch" /> <!-- 關鍵就是這一行了-->
</div>
</form>
同時還增加了一個#patch
方法,可以在合適的時候使用:
test "update book with PATCH verb" do
patch :update, id: @book, book: { title: @book.title }
assert_redirected_to book_url(@book)
end
Concerns(關注點)是一種組織代碼結構的方式,用來幫助開發者將復雜的邏輯和重複代碼梳理清楚,我們在Rails 4 中多次看到對於Concerns 的設計和實現。先看一段老代碼:
resources :messages do
resources :comments
resources :categories
resources :tags
end
resources :posts do
resources :comments
resources :categories
resources :tags
end
resources :articles do
resources :comments
resources :categories
resources :tags
end
像這樣的代碼存在許多的重複,Rails 4 允許我們重構它:
concern :sociable do
resources :comments
resources :categories
resources :tags
end
resources :messages, concerns: :sociable
resources :posts, concerns: :sociable
resources :articles, concerns: :sociable
可以通過傳遞參數來實現對個例的特化:
concern :sociable do |options|
resources :comments, options
resources :categories, options
resources :tags, options
end
resources :messages, concerns: :sociable
resources :posts, concerns: :sociable
resources :articles do
concerns :sociable, only: :create
end
甚至我們可以抽取出來變成單獨的類:
# app/concerns/sociable.rb
class Sociable
def self.call(mapper, options)
mapper.resources :comments, options
mapper.resources :categories, options
mapper.resources :tags, options
end
end
# config/routes.rb
concern :sociable, Sociable
resources :messages, concerns: :sociable
resources :posts, concerns: :sociable
resources :articles do
concerns :sociable, only: :create
end
我們都聽說Rails 4 需要Ruby 的版本不能小於1.9.3,不過這一點所引起的變化通常都十分微妙,不容易讓人注意到。
1.8.x 時代,nil.id
是合法的(一切都是對象!),但是不合理,經常惹人厭。於是1.9.2 之後,逐漸使用object_id
來代替,使用舊的id
方法會拋出運行時錯誤:
RuntimeError: Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
Rails 3 無法永遠擺脫這惱人的提示,因為它要同時兼容1.8 和1.9,於是一旦碰上可能會出現的nil.id
就會看到上面那個錯誤
在Rails 4 的世界裡,手起刀落,喀嚓~~~ 從此nil 不再聒噪,世界終於清淨了……
NoMethodError: undefined method `id' for nil:NilClass
線程安全的處理在Rails 3 中已有,不過默認是關閉的:
# config/environments/production.rb
MyApp::Application.configure do
# Enable threaded mode
# config.threadsafe!
end
這個方法在Rails 4 中不推薦使用,新的線程安全機制在默認情況下就已經開啟:
# config/environments/production.rb
MyApp::Application.configure do
config.cache_classes = true # 阻止類在請求中重新載入,並保證Rack::Lock 不包含在中間件堆棧中
config.eager_load = true # 在新線程創建前加載全部代碼
end