Rails Metal指南

今天在Metal中用到了读取当前登录用户current_user的方法,于是找到了下面这篇文章,虽然是09年的,但是价值依旧在,翻译一下,以备后用

[b]Rails Metal使用指南[/b]

[b]Posted by mikong on February 03, 2009[/b]

当我在使用Rails Metal写程序的时,才发现我已经被Rails带来的便利所宠坏了,没有了controller和view helpers,简直太痛苦了。希望这个指南能给您带来更好的体验。
在这个指南中,我们会写一个Widget Refresher Metal的小程序,假设我们的rails工程中的widget页面访问次数非常多,并且我们想充分发挥使用Metal的优势。那么在我们的工程的 app/metal 目录下,创建 refresher.rb

  
class Refresher < Rails::Rack::Metal
def self.call(env)
refresher = RefresherApp.new
refresher.call(env)
end
end

class RefresherApp
def call(env)
# refresh widget path: /widgets/:id/refresh
if env["PATH_INFO"] =~ /^\/widgets\/(\d+)\/refresh/
widget_id = $1
prepare(env, widget_id)
refresh
else
[404, { "Content-Type" => "text/html" }, "Not Found"]
end
end

# to setup the environment
def prepare(env, widget_id)
...
end

# the heart of our Metal app
def refresh
...
end
end


相比较把所有的代码都写在Refresher类(继承自Rails::Rack::Metal)里面,我更喜欢创建一个单独的RefresherApp类。当你的Metal程序已经不再是平凡简单的HelloWorld的时候,需要一大串相互调用的方法, 因为这个call方法在这个Metal程序中是一个类方法,把所有的代码放在一个类里面将意味着所有的这些方法都将是一些类方法。但是我觉得那样太丑陋了。如果你想,尽管把这些代码放在一个类里面。如果真的打算这么做,你可以设置上下文为self的,这样就没有必要在每一个方法前面加一个“self.”了。

class Refresher < Rails::Rack::Metal

# the methods in here are class methods
class << self
def call(env)
...
end

def method
...
end
end

end


另外,在开发Metal程序的时候需要注意,为确保你的代码变化生效你需要持续的重启你的服务。.

[b]Request和Session[/b]

你可以通过下面这些代码,访问request以及它里面的参数


request = Rack::Request.new(env)
params = request.params
params['mykey'] # String keys, so not params[:mykey]


正如你所看到的,这些 keys 是字符串实例,而不是Symbol。
对于session则可以这样得到

session = env['rack.session']


你可以吧所有的这些代码一移动到prepare方法中。此外,我们可以设置params[:id](如果你愿意你可以使用Symbol),我们的主refresh方法中,看起来像是一个rails的controller。通过session我们可以得到当前用户。同样我们可以像在rails controller中写方法一样去定义其他方法。正如下面所示:


attr_reader :request, :session, :current_user

def params
@request.params
end

def logged_in?
!!current_user
end

def prepare(env, widget_id)
@request = Rack::Request.new(env)
params[:id] = widget_id
@session = env["rack.session"]
@current_user = session[:user_id] ? User.find(session[:user_id]) : false
end



做了这些准备工作,我们可以开始写这个叫做refresh的主方法了

[b]refresh 和 ActiveRecord[/b]

假设,在客户端,我们只需要返回widget 的status属性

def refresh
@widget = Widget.find(params[:id])

return [200, { "Content-Type" => "text/html" }, @widget.status]
end

只要确保格式正确,你同样可以给客户端返回javascript或者其他类型的内容。另外可以添加简单的检查用户是否登录的校验

def refresh
@widget = Widget.find(params[:id])

if logged_in?
return [200, { "Content-Type" => "text/javascript" }, "Element.update('status', '#{@widget.status}');"]
else
return [200, { "Content-Type" => "text/javascript" }, "Element.update('message', 'Must be logged in for widget status to refresh');"]
end
end


但是在返回一个比较复杂的javascript的时候,最好还是避免回车和引号,否则在浏览器这边我们会解析错误,rails提供了一个叫做escape_javascript的方法,但是Metal程序中默认情况下是不能访问的。

[b]View Helpers[/b]

要想在Metal程序中使用helper,只需要引用(include)你所需要的modules的就可以了

include ActionView::Helpers::JavascriptHelper # so escape_javascript works
include WidgetsHelper # for example

但是我更倾向于避免使用这些帮助方法

[b]Request Forgery Protection[/b]
伪请求防护

如果不是get请求的request,你需要辨别authenticity token的真假

可以实现的一种方法:

def refresh
# before everything else
return redirect_to_widgets_response unless verified_request?

# everything else
...
end

def redirect_to_widgets_response
return [302, { "Content-Type" => "text/html", "Location" => "/widgets" },
"<html><body><a href=\"/widgets\">Redirecting...</a></body></html>"]
end

# Based on Rails method of the same name but simplified, i.e. no need to check if:
# - protection is disabled
# - request method is :post
# - format is verifiable
def verified_request?
form_authenticity_token == params['authenticity_token']
end

def form_authenticity_token
session[:_csrf_token] ||= ActiveSupport::SecureRandom.base64(32)
end

[b]更多的挑战[/b]

在写自己的Rail Metal程序的时候,你可能会遇到其他的一些挑战,我已经尝试直接使用ERB来渲染一个模板,但感觉还是不要在这里献丑了。但是我已经尽力了。不是所有的业务逻辑可以这么快的专程Metal程序。简单的事情建议这么做,否则就太得不偿失了。不管怎样,希望这篇指南可以帮你解决一些问题。当然,如果你有什么好的建议可以提。

------------
欢迎指正建议,谢谢

原文地址
[url]http://devblog.michaelgalero.com/2009/02/03/guide-to-rails-metal/[/url]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值