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