-
<div>
-
<ul>
-
<li> lalalalala </li>
-
<li><strong><a href="http://www.google.com"> Google
-
</a>
-
</strong>
-
</li>
-
</ul>
-
</div>
拆分数组
Ruby 中的 Array 类提供了非常实用的 select 和 reject 方法,可以方便的从数组中挑出或剔除符合条件的元素:
-
a = [1,2,3,4,5,6,7,8]
-
a.select {|x| x % 2 == 0}
-
>> [2,4,6,8]
如果想要把数组拆分成两个集合,一个符合某个条件,一个不符合,要怎么办呢?
可以先写一个 select 然后再来个 reject:
-
a = [1,2,3,4,5,6,7,8]
-
even = a.select {|x| x % 2 == 0}
-
odd = a.reject {|x| x % 2 == 0}
-
>> even = [2,4,6,8]
-
>> odd = [1,3,5,7]
这样的话,不仅条件要重复写两遍,数组中的元素也要遍历两遍 。
可以利用 Ruby 可以返回多个值的特性,来写个 separate 函数:
-
class Array
-
def separate
-
yes, no = [], []
-
-
self.each do |x|
-
yield(x) ? yes << x : no << x
-
end
-
-
return yes, no
-
end
-
end
这样,数组拆分一次就可以搞定了 :
-
even, odd = a.separate {|x| x % 2 == 0}
return false 在 IE 下失效了?
link_to 有个 method 属性,经常拿来配合 confirm 属性做删除链接:
其实就是在链接的 onclick 中创建了一个临时表单,提交请求,最后 return false,这样链接本身就不会被触发:
不过发现,在 IE 下这个 return false 并没有效果,onclick 中的表单提交了,链接也触发了,以上面这个为例,点这个链接,会向 /admin/destroy/1234 发送两次请求,一次 post 一次 get 。
那么为什么原来没有发现这个问题呢,因为 Rails 生成的控制器代码中都会有这么一句:
verify :method => :post, :only => [ :destroy, :create, :update ], :redirect_to => { :action => :list }
所以第二次错误的 get 请求就会被转到 list 方法上去,但是即使通过 post 删除成功后,大多数情况也会转到 list 上去,看起来是一样的汗,实际上被转了两次。
问题就在于 IE 忽略了 return false,google 了下,好像碰到这个问题的人不是很多汗,难道是我 rp 问题…… 最后搜到了这个:
onclick="return false;" don't work in IE
看来有人在 CakePHP 的 AjaxHelper 中也发现了这个问题,解决的方法就是在 return false 前面加上一句:
这样问题就解决了,不过 Rails 链接的 onclick 都是自动生成的,要怎么改呢。
再次拜 Ruby 强大的 OpenClass 所赐:
-
module ActionView
-
module Helpers
-
module UrlHelper
-
private
-
def convert_options_to_javascript!(html_options, url = '')
-
...
-
when confirm && popup
-
"... ;event.returnValue = false; return false;"
-
when confirm && method
-
"... ;event.returnValue = false; return false;"
-
...
-
when method
-
"... event.returnValue = false;return false;"
-
when popup
-
... + 'event.returnValue = false;return false;'
-
...
-
end
-
end
-
end
找到 conver_options_to_javascript 这个方法,copy 过来,再添加上高亮部分的代码即可。直接覆盖核心的 private 方法,这种事情干起来真爽……
自动闭合 html 标签简化版
Chito 现在用 Rubyful Soup 来解决 html 没有正确闭合的问题,其中的 BeautifulSoup 类的 prettify 方法非常强大,几乎可以修正 html 中的所有错误。
不过 Chito 只是拿来闭合标签,其他的功能完全用不到,Rubyful Soup 还要依赖 htmltools 这个库,为了个闭合标签就要多附带这么多库太不爽了,而且还有个 %nbsp 的 bug。
自己尝试写了个,close_html:
-
def close_html(html)
-
stream = html.scan( /<\s*[^>]+>/ ).map {|x| x[ /<\s*([^>^\s]*)[^>]*>/ , 1]}
-
stack = []
-
stream.each do |x|
-
if x =~ /^\//
-
stack.pop if x[1..-1] == stack.last
-
else
-
stack.push x
-
end
-
end
-
stack.reverse.each {|x| html << "</#{x}>\n"}
-
html
-
end
处理的方式罗嗦了一些,先把 html 文本中的标签提取出来,然后再去掉属性之类的,转换成一个 “标签流”,比如:
<div class="main><ul><li>test</li>
就转换成了:
["div","ul","li""/li"]
接着读取上面这个流,把开始标签压栈,遇到以 / 开头的结束标签,检查是否和栈顶的标签相匹配,匹配就弹出,走完标签流后,还留在栈里的标签就是需要闭合的标签了。
测试一下:
-
test_html = <<END
-
<div>
-
<ul>
-
<li> lalalalala </li>
-
<li><strong><a href="http://www.google.com"> Google
-
END
-
-
puts close_html(test_html)
输出:
效果不错,标签都正确闭合了~
这种方法还是有局限性的,因为只是个简单的栈操作,所以只适合修正那些正确的 html 被拦腰截断的情况,而不能修正类似 <h1></h2> 这样匹配错误的情况,<div><a></div> 这样中间格式错误的情况也不行,不过 Chito 的编辑器和 textile 都不会生成这些样子的 html,所以完全可以用这个小函数替代那个庞大的 Rubyful Soup 了~
原来有个 reset_session
之前在用户登出的时候,都手动小心的清除登录用户的 session,今天才发现有 reset_session 这个方法,一口气把当前 session 对象的内容全部清除,又方便又安全~
reset_session - Resets the session by clearing out all the objects stored within and initializing a new session object.
不光用户登出时要清空 session,用户登入之前,也要清除 session,免除当前 session 数据,和恶意伪造 session 数据的影响:
-
def login
-
...
-
if user.try_to_login
-
reset_session
-
session[:user_id] = user.id
-
...
-
-
def logout
-
reset_session
-
redirect_to 'xxx'
-
end
Ruby 中获取目录大小
查了查,Dir 类没有 size 方法,也没找到现成的解决方案,自己动手吧~
当前 Chito 中统计目录大小完全是偷懒的方式 :
-
class Dir
-
def self.size(dir)
-
`du -s #{dir} | awk '{print $1}'`.to_i
-
end
-
end
直接调用 du 这个程序然后把结果转换成数值就可以了,非常方便~ 不过要是运行在 Windows 下就不灵了,只好自己写代码统计下:
-
class Dir
-
def self.size(dir)
-
sum = 0
-
Dir.foreach(dir) do |entry|
-
next if entry =~ /^\./
-
path = File.join(dir, entry)
-
FileTest.directory?(path) ? sum += Dir.size(path) : sum += File.size(path)
-
end
-
sum
-
end
-
end
不过计算目录大小是个很慢的工作,尤其时文件夹嵌套很深,小文件又很多的时候,缓存一下是很必要的,当新文件上传或者删除设置个 dirty 标记,dirty 标记存在的时候再去重新获取。