Rails 3,HTTP扩展(WebDAV)和Rack App安装

1以下更多内容是指代代码开发了一个可以被认为是缺陷的rails的问题。
2我也问过一些了解得更好的人的一些观点。

我想通过Warden身份validation将WebDAV添加到我的Rails 3应用程序中。 我的warden中间件是通过Devise注入的。

http://github.com/chrisroberts/dav4rack
http://github.com/hassox/warden
http://github.com/plataformatec/devise

我无法从rails app(routes)中挂载DAV4Rack处理程序,如下所示:

# in config/routes.rb mount DAV4Rack::Handler.new( :root => Rails.root.to_s, #  '/webdav', :resource_class => Dav::DocumentResource #  "/webdav" 

因为railsvalidationHTTP谓词(GET POST PUT ..),而webdav使用像PROPFIND这样的HTTP扩展不能validation,抛出以下exception:

 ActionController::UnknownHttpMethod (PROPFIND, accepted HTTP methods are get, head, put, post, delete, and options) 

此validation发生在ActionDispatch中:

 /usr/local/lib/ruby/gems/1.9.1/gems/actionpack-3.0.0/lib/action_dispatch/http/request.rb +56 +72 in (56) "def request_method" and (72) "def method" 

来自ActionDispatch的示例代码,用于执行validation,以明确说明:

 def method @method ||= begin method = env["rack.methodoverride.original_method"] || env['REQUEST_METHOD'] HTTP_METHOD_LOOKUP[method] || raise(ActionController::UnknownHttpMethod, "#{method}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(:locale => :en)}") method end end 

从理论上讲,我们可以对这个validation进行修补,以符合webdav谓词,例如railsdav项目 (注意那里是rails 2,在rails 3中需要使用monkey-patch action_dispatch / http / request)。

要将DAV4Rack处理程序添加到rails应用程序,我必须在ActionDispatch之外,在机架级别安装处理程序,如下所示:

 # config.ru require ::File.expand_path('../config/environment', __FILE__) require 'dav4rack/interceptor' require 'dav/document_resource' app = Rack::Builder.new{ map '/webdav/' do run DAV4Rack::Handler.new( :root => Rails.root.to_s, :root_uri_path => '/webdav', :resource_class => Dav::DocumentResource ) end map '/' do use DAV4Rack::Interceptor, :mappings => { '/webdav/' => { :resource_class => Dav::DocumentResource }, } run Pmp::Application end }.to_app run app 

现在我在我的应用程序中有Webdav支持。 但它仍然需要身份validation,为此我想使用warden。

 # in document_resource.rb def check_authentication puts request.env['warden'] # nil :( end 

Warden是零,因为我的DAV4Rack :: Handler安装在会话之上并且监控中间件。 使用“rake middleware”来检查我的堆栈,我可以看到以下内容:

 > rake middleware use ActionDispatch::Static use Rack::Lock use ActiveSupport::Cache::Strategy::LocalCache use Rack::Runtime use Rails::Rack::Logger use ActionDispatch::ShowExceptions use ActionDispatch::RemoteIp use Rack::Sendfile use ActionDispatch::Callbacks use ActiveRecord::ConnectionAdapters::ConnectionManagement use ActiveRecord::QueryCache use ActionDispatch::Cookies use ActionDispatch::Session::CookieStore use ActionDispatch::Flash use ActionDispatch::ParamsParser use Rack::MethodOverride use ActionDispatch::Head use ActionDispatch::BestStandardsSupport use Warden::Manager run Pmp::Application.routes 

我相信通过使用DAV处理程序包装“Pmp :: Application.routes”(就像我在上面为config.ru中的“Pmp :: Application”所做的那样)将在我的webdav处理程序注入正确的位置来满足这两个条件:

  1. 在ActionDispatch方法validation代码之上,以避免ActionController :: UnknownHttpMethod
  2. 低于会话和Warden :: Manager,所以我可以使用warden身份validation。

怎么做? 看看“rake middleware”输出,覆盖“Pmp :: Application.routes”方法似乎很明显:

 # in my app at APP_ROOT/config/application.rb # override the routes method inherited from Rails::Application#routes def routes routes_app = super app = Rack::Builder.new { map '/webdav/' do run DAV4Rack::Handler.new( :root => Rails.root.to_s, :root_uri_path => '/webdav', :resource_class => Dav::DocumentResource ) end map '/' do use DAV4Rack::Interceptor, :mappings => { '/webdav/' => { :resource_class => Dav::DocumentResource }, } run routes_app end }.to_app class << app; self end.class_eval do attr_accessor :routes_app def method_missing(sym, *args, &block) routes_app.send sym, *args, &block end end app.routes_app = routes_app app end 

因为我们的新机架应用程序“应用程序”将被问及链中的一些方法,即旧的机架应用程序“routes_app”用于重新发送,我们将theese委托给旧的原始应用程序“routes_app”,带有一点method_missing魔法。

瞧:一切正常! 巨大的成功。

只有一个问题:我不喜欢它。 除了覆盖路线方法之外,必须有更好的方法来完成所有这些包络。

请注意,这不适用于乘客。 最好的方法似乎是猴子修补铁轨。
请参阅: dav4rack wiki

大问题:

有没有更好的方法添加一个机架应用程序上面的“Pmp ::应用程序#路由”APP通过机架或其他方式???

大结论

  1. routes.rb中的“mount”语义应该是机架级(而不是rails / railtie / whatever),以这种方式允许对HTTP扩展进行处理,或者至少为这种情况设置一个方法“mount_rack”