Rails Metal指南_Ruby_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > Ruby > Rails Metal指南

Rails Metal指南

 2011/1/18 8:04:41  hotsunshine  http://hotsunshine.javaeye.com  我要评论(0)
  • 摘要:今天在Metal中用到了读取当前登录用户current_user的方法,于是找到了下面这篇文章,虽然是09年的,但是价值依旧在,翻译一下,以备后用RailsMetal使用指南PostedbymikongonFebruary03,2009当我在使用RailsMetal写程序的时,才发现我已经被Rails带来的便利所宠坏了,没有了controller和viewhelpers,简直太痛苦了。希望这个指南能给您带来更好的体验。在这个指南中,我们会写一个WidgetRefresherMetal的小程序
  • 标签:rails
今天在Metal中用到了读取当前登录用户current_user的方法,于是找到了下面这篇文章,虽然是09年的,但是价值依旧在,翻译一下,以备后用

Rails Metal使用指南

Posted by mikong on February 03, 2009

    当我在使用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程序的时候需要注意,为确保你的代码变化生效你需要持续的重启你的服务。.

Request和Session

你可以通过下面这些代码,访问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的主方法了

refresh 和 ActiveRecord

假设,在客户端,我们只需要返回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程序中默认情况下是不能访问的。

View Helpers

要想在Metal程序中使用helper,只需要引用(include)你所需要的modules的就可以了
  include ActionView::Helpers::JavascriptHelper # so escape_javascript works
  include WidgetsHelper # for example

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

Request Forgery Protection
伪请求防护

如果不是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

更多的挑战

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

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

原文地址
http://devblog.michaelgalero.com/2009/02/03/guide-to-rails-metal/
发表评论
用户名: 匿名