Rails 曾经迷惑的小知识二

以下都是参考自:Ruby on Rails 实战圣经,里面有很多好用的小知识,也是曾经走过的坑,一点点知道的,这里面给整理的很好。(因为部署在台湾吧,所以加载很慢,等等就会加载出来网页了)

Unobtrusive JavaScript

Rails 使用一种叫做 Unobtrusive JavaScript(UJS) 的方式來加载內建的 JavaScript 功能,也就是你在 app/assets/javascripts/application.js 里面载入的 //= require jquery_ujs,这些功能包括

  • 让超链接可以用 :method 参数支援非 GET 方法
  • 用超链接、按钮和表单可以用 remote: true 支援 Ajax
  • 超链接、按钮和表单可以用 data-confirm 参数可以弹出确认对话框
  • 送出按钮可以用 data-disable-with 参数在送出表单时暂时关闭按钮避免重复发送

什么是 Unobtrusive 呢?用个例子來说吧,以下代码会将超链接改成用表单 DELETE 送出,并且用一个提示弹窗来作确认:

1
link_to 'Remove', event_path(1), :method => :delete, :data => { :confirm => "Sure?" }

在Rails 3以前的版本,会输出:

1
<a onclick="if (confirm('Sure?')) { 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', 'delete'); f.appendChild(m);f.submit(); };return false;" href="/events/1">Remove</a>

Rails 3 之后,会输出:

1
<a rel="nofollow" data-confirm="Sure?" data-method="delete" class="delete" href="/events/1">Remove</a>

Unobtrusive 也就是将 JavaScript 程式与HTML完全分开,除了可以让HTML代码干净之外,也可以支援更换不同的 JavaScript Library,例如把 Rails 內建的 jQuery 換成 Protytype.jsangular.js 等等。

Layout 中有輸出一段 <%= csrf_meta_tag %> 的作用就是搭配给 UJS 使用的,让 JavaScript 可以拿到 CSRF 安全验证码。

j()escape_javascript() 的缩写

Ajax 的三种使用方式

AjaxAsynchronous JavaScript and XML 的缩写,是一种不需要重新整理页面,通过 JavaScript 来与服务器交换资料、更新网页內容的技术。目的在于改善使用者的操作界面,提升流畅度。它主要是通过浏览器提供的 XMLHttpRequestObject 来达成,不过因为要支援跨浏览器,大多数人們会选择使用 JavaScript Library 来处理 Ajax,例如最流行的 JQuery

总体来说,依照 Ajax 使用的格式分类,有三种方式:

向服务器请求 HTML 片段,然后客户端浏览器上的 JavaScript 再替换掉页面上的元素
向服务器请求 JavaScript 程式脚本,然后客户端浏览器执行它
向服务器请求 JSONXML 资料格式,然后客户端浏览器的 JavaScript 解析后再动作。

具体三种方式请参考:Ajax 應用程式 很详细。

其他实用的方法

pluralize 方法可以帮我们将名词字串转为复数的名词:

1
2
3
"table".pluralize # => "tables"
"ruby".pluralize # => "rubies"
"equipment".pluralize # => "equipment"

singularize 方法则是可以帮我们转为单数:

1
2
3
"tables".singularize # => "table"
"rubies".singularize # => "ruby"
"equipment".singularize # => "equipment"

camelize 可以帮我们将字串转为驼峰式的字串:

1
2
"product".camelize # => "Product"
"admin_user".camelize # => "AdminUser"

Rails 中也会将路径中 ”/” 符号转为 ClassModule 中的命名空间符号::

1
"backoffice/session".camelize # => "Backoffice::Session"

underscore 则是将原先驼峰式的字串转为路径式的字串:

1
2
3
"Product".underscore # => "product"
"AdminUser".underscore # => "admin_user"
"Backoffice::Session".underscore # => "backoffice/session"

titleize 方法可以将字串标题化,将单字的开头皆转为大写:

1
2
"alice in wonderland".titleize # => "Alice In Wonderland"
"fermat's enigma".titleize # => "Fermat's Enigma"

dasherize 可以将字串中的底线转为横线:

1
2
"name".dasherize # => "name"
"contact_data".dasherize # => "contact-data"

demodulize 可以将整串的 namespace 去除仅留下最后的 Class name 或是 Module name :

1
2
"Backoffice::UsersController".demodulize # => "UsersController"
"Admin::Hotel::ReservationUtils".demodulize # => "ReservationUtils"

deconstantize 则是相反的作用,将上层的部分全部找出来:

1
2
"Backoffice::UsersController".deconstantize # => "Backoffice"
"Admin::Hotel::ReservationUtils".deconstantize # => "Admin::Hotel"

必须注意的是这是处理字串,因此若直接仅给予 Class name 或是 Module name 是无法找出上层参照的

1
"Product".deconstantize # => ""

parameterize 可以将字串转为适合 url 的方式:

1
2
"John Smith".parameterize # => "john-smith"
"Kurt Gödel".parameterize # => "kurt-godel"

tableize 除了会将单数名词转为复数之外,还会将驼峰式的名词改为底线:

1
"InvoiceLine".tableize # => "invoice_lines"

tableize 的作用其实在于帮助你找出 Model 的资料表名称

classify 则是 tableize 的相反,能够帮你从资料表的名称转为 Model :

1
2
3
"people".classify # => "Person"
"invoices".classify # => "Invoice"
"invoice_lines".classify # => "InvoiceLine"

humanize 可以帮你将Model的属性转为较容易阅读的形式:

1
2
3
"name".humanize # => "Name"
"author_id".humanize # => "Author"
"comments_count".humanize # => "Comments count"

扩充 Enumerable

index_by
index_by 可以帮我们将集合元素以指定的栏位做为键值整理成 Hash :

1
2
3
invoices.index_by(&:number)
# => {'2009-032' => <Invoice ...>, '2009-008' => <Invoice ...>, ...}
键值通常必须是唯一的,若不是唯一的话将会以最后出现的元素做为判断值。

many?
many? 是可个好用的方法可以帮助我们快速的判断集合的数量是否大于1:

1
2
3
<% if pages.many? %>
<%= pagination_links %>
<% end %>

如果对 many? 传入区块运算时,many? 仅会回传运算结果是true的结果:

1
@see_more = videos.many? {|video| video.category == params[:category]}

还有些实用的小方法,抄过来太多了,请查看 ActiveSupport - 工具函式库