Ga Tech

1.01 everyday

Rails 4

紀錄 Rails 3 to Rails 4 的一些改變。

MATCH ROUTES

以往 Rails 3 的 match 寫法:
match ‘/items/:id/purchase’, to: ‘items#purchase’
因為語意不清,不知道是 put、get、post 或 delete 等 HTTP method,且容易遭受 XSS 攻擊,因此在 Rails 4 會要求指定 HTTP method,否則就會造成 RuntimeError。
假設我們要指定 post HTTP method,就要寫成:
post ‘/items/:id/purchase’, to: ‘items#purchase’
或是
match ‘/items/:id/purchase’, to: ‘items#purchase’, via: :post
如果真的是要指定所有 HTTP method 的話,就寫成:
match ‘/items/:id/purchase’, to: ‘items#purchase’, via: :all

PATCH VERB

Rails 3 對應 update 動作的 HTTP method 只有 PUTPUT 會傳遞整個 resource 來進行 update,但如果只想要 update resource 的某些 attribute,這樣就造成浪費了。
Rails 4 使用 PATCH 來解決此一需求。(在 HTTP 1.1 的時候就有這個 method 了)

可惜的是,並非所有瀏覽器都支援 PATCH method,Rails 4 提供了折衷辦法:

1
2
3
form_for(@item) do |f|
...
end

會產生

1
2
3
4
5
6
<form action="/items/20" method="post">
<div>
<input name="utf8" type="hidden" value="&#x2713;" />
<input name="_method" type="hidden" value="patch" />
</div>
</form>

Rails 4 在 form 上面仍然使用 post method,但裡頭多了一個 hidden 來指定 patch method。這樣一來就能支援所有瀏覽器,而 Rails 自己也能根據 hidden field 的 value 瞭解到這是 patch method。

此外,在 test 當中也新增了 patch method:

1
2
3
4
5
test "updates item with PATCH" do
patch :update, id: @item,
item: { description: @item.description }
assert_redirected_to item_url(@item)
end

CONCERNS

在 route 裡頭有時候會遇到同樣的 resources 出現好幾次,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
resources :messages do
resources :comments
resources :categories
resources :tags
end
resources :posts do
resources :comments
resources :categories
resources :tags
end
resources :items do
resources :comments
resources :categories
resources :tags
end

遇到這種情形時,可以用 concern 包起來,並給定一個名字(sociable)以便維護:

1
2
3
4
5
6
7
8
9
concern :sociable do
resources :comments
resources :categories
resources :tags
end
resources :messages, concerns: :sociable
resources :posts, concerns: :sociable
resources :items, concerns: :sociable

concern 也可以傳入參數,比如只要讓 sociable 可以在 items 底下 create:

1
2
3
4
5
6
7
8
9
10
11
concern :sociable do |options|
resources :comments, options
resources :categories, options
resources :tags, options
end
resources :messages, concerns: :sociable
resources :posts, concerns: :sociable
resources :items do
concerns :sociable, only: :create
end

concern 甚至可以抽出來包成 object。要注意的是,這個 object 必須能夠 respond_to call

app/concerns/sociable.rb
1
2
3
4
5
6
7
class Sociable
def self.call(mapper, options)
mapper.resources :comments, options
mapper.resources :categories, options
mapper.resources :tags, options
end
end
1
2
3
4
5
6
7
concern :sociable, Sociable
resources :messages, concerns: :sociable
resources :posts, concerns: :sociable
resources :items do
concerns :sociable, only: :create
end

TREAD-SAFETY

在 Rails 3 當中,thread safety 預設是被關掉的:

config/environments/production.rb
1
2
3
4
MyApp::Application.configure do
# Enable threaded mode
# config.threadsafe!
end

而在 Rails 4 裡,thread safety 預設是打開的,上面兩個設定也被拿掉,並且另外加入了兩個設定:

config/environments/production.rb
1
2
3
4
MyApp::Application.configure do
config.cache_classes = true
config.eager_load = true
end

第一個設定是確保 class 在兩個 requests 之間,不會被 reload,並確保 middleware stack 沒有包含 Rack::Lock,這樣一來,threads 就不會被 lock 住了。
另一個設定則是讓新的 threads 建立之前,所有的 code 都已經被 load 完畢以供我們使用。

為了盡可能讓 multi-threaded 表現更好,可以使用 Puma
對於 multi-threaded server 的選擇,這篇 文章有不錯的講解。

source: CodeSchool

Comments