拥抱 Rails 4_1


## Routes

### 小心地使用 Match（Rails 3 已实现）

Rails 3 提供了 `match` 方法供我们自定义 routes，然而我们要小心使用它以避免“跨站脚本攻击”（XSS Attack）。比如像这样的 routes：

_注：（r3 代表 Rails 3，r4 代表 Rails 4）_

```ruby
# routes.rb
match '/books/:id/purchase', to: 'books@purchase'
```

用户可以很轻松地使用 <del>XSS Attack</del> CSRF Attack，比如使用这样一个链接：

> CodeSchool 的 Rail 4 教程里写的是 XSS Attack，经查证和问询，证明这是 CodeSchool 的失误，应该会很快改正过来，再次先做一个修正，并向受到误导的朋友致歉

```html
<a href="http://yoursite.com/books/4/purchase">Get It Free!</a>
```

这会使用 GET 去请求这个资源，你绝对不想看到这种情况（你希望的是 POST），所以你要限制客户端可以访问此资源的方式。例如：

```ruby
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)

---

### 新的 HTTP Verb：patch

过去我们使用 `put` 来完成对资源的更新请求，然而 `put` 本身是对整个资源（数据集合）进行更新，若要实现部分资源的更新（单个数据，或是几个产生变化的数据实体），`put` 就有点过重了，此时 `patch` 会更加合适。

`patch` 并不是什么新东西，此前就一直存在于 HTTP 1.1 协议规范之中，只不过这一次 Rails 4 把它正式的引入进来。在 Rails 4 中，`put` 和 `patch` 都指向 `controller#update`，在更新部分资源时（比如 @book）会使用 `patch`，生成类似下例中的页面元素：

```html
<form action="/books/20" method="post">
  <div style="margin:0;padding:0;display:inline">
  <input name="utf8" type="hidden" value="&#x2713;" />
  <input name="_method" type="hidden" value="patch" /> <!-- 关键就是这一行了 -->
  </div>
</form>
```

同时还增加了一个 `#patch` 方法，可以在合适的时候使用：

```ruby
test "update book with PATCH verb" do
  patch :update, id: @book, book: { title: @book.title }
  assert_redirected_to book_url(@book)
end
```

---

### Concerns for Routing

Concerns（关注点）是一种组织代码结构的方式，用来帮助开发者将复杂的逻辑和重复代码梳理清楚，我们在 Rails 4 中多次看到对于 Concerns 的设计和实现。先看一段老代码：

```ruby
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 允许我们重构它：

```ruby
concern :sociable do
  resources :comments
  resources :categories
  resources :tags
end

resources :messages, concerns: :sociable
resources :posts, concerns: :sociable
resources :articles, concerns: :sociable
```

可以通过传递参数来实现对个例的特化：

```ruby
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
```

甚至我们可以抽取出来变成单独的类：

```ruby
# 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
```

## 抛弃 Ruby 1.8.x

我们都听说 Rails 4 需要 Ruby 的版本不能小于 1.9.3，不过这一点所引起的变化通常都十分微妙，不容易让人注意到。

### 聒噪的 nil

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 中已有，不过默认是关闭的：

```ruby
# config/environments/production.rb
MyApp::Application.configure do
  # Enable threaded mode
  # config.threadsafe!
end
```

这个方法在 Rails 4 中不推荐使用，新的线程安全机制在默认情况下就已经开启：

```ruby
# config/environments/production.rb
￼MyApp::Application.configure do
  config.cache_classes = true # 阻止类在请求中重新载入，并保证 Rack::Lock 不包含在中间件堆栈中
  config.eager_load = true # 在新线程创建前加载全部代码
end
```