WebDAV Ruby On Rails Plugin

June 25th, 2006

The moment a few of you have been waiting for.

I’m releasing the first version of the RailsDAV plugin. What does RailsDAV do. Well it allows people to create Ruby On Rails controllers which will respond to WebDAV requests and expose functionality as a file-system.

The plugin can be downloaded from

http://svn.liverail.net/svn/plugins/railsdav

Of course the great thing about WebDAV is that it doesn’t just need to expose a directory on your server but can expose any concept you have in your application. For instance, for a Digital Asset Management System expose a list of tags as directory names, navigate into that directory and see all the images tagged with that word.

I’ll write about using the plugin in just a second, but first a little wording. This is definitely a 0.1 release and still needs work and a lot of testing before being production ready. It is likely to take on a different shape as well. It has many problems under WebBrick but works very very nicely under Mongrel (this is a problem with WebBrick) But release early, release often huh!

The plugin contains a base WebDAV controller and 2 specific implementations. A file-system exposer and an ActiveRecord exposer.

With thanks to Fabien Franzen for his input so far

There is also video of the FileSystem WebDAV Controller and the ActiveRecord WebDAV Controller

FileWebDavController

The file system webdav controller can be used by creating a controller in your app/controllers directory.

And in the routes.rb add

RAILS_ROOT to expose for read/write operations.

To add some HTTP Basic Authentication security you can do

class MyStoreController < Railsdav::FileSystem::FileWebDavController set_max_propfind_depth 1 set_rails_webdav_root "directory_under_rails" before_filter :my_auth def my_auth() basic_auth_required {|username, password| session[:user] = User.your_authentication(username,password) } end end

Start your server. Mongrel is the best if you have it, if you havn’t try

sudo gem install mongrel cd myrailsapp mongrel_rails start -d

To connect you point your webdav client to http://localhost:3000/mystore/

This includes the MacOSX Connect To Server and Windows WebPlaces or what ever they call them.

ActiveRecordWebDavController

The active record webdav controller is an example of how you can expose things that are not a filesystem over webdav.

Basically it displays all the ActiveRecord models as directories. Access a directory and all the records are shown as YAML files.

class DbStoreController < Railsdav::ActiveRecord::ActiveRecordWebDavController set_max_propfind_depth 1 end

And in the routes.rb add

map.connect 'dbstore/*path_info', :controller => 'db_store', :action => 'webdav'

20 Responses to “WebDAV Ruby On Rails Plugin”

  1. Stoyan Zhekov Says:

    Seems you was in a harry – too many typos in the post:

    1. def MyStoreController < Railsdav::FileSystem::FileSystemWebDavController

    is maybe better to be (class, not def, FileWebDavController, not FileSystem….)

    class MyStoreController < Railsdav::FileSystem::FileWebDavController

    2. in routes.rb:

    :action => ‘webdav’ (not ‘weddav’)

    Except that, the plugin is working great, thanks a lot for it.

  2. Stuart Eccles Says:

    Thanks for the proof-read ;-) I’ve corrected the post.

    Enjoy. There is likely to be a few bugs in the plugin too, it isn’t final yet

  3. tom winkler Says:

    Great Stuff! Thank you!

  4. railsprogrammer.com Says:

    Great release… I had been thinking integrated webdav would be perfect for my project… ;)

    I’m getting the following error trying to use the file system exposer.

    This was using the 1.15 gem for the required “mime/types” include—is that the right idea?

    Parameters: {"format"=>#<mime::type:0xb7830b30>, "path_info"=>[], "exception"=>"can't typecast \"DAV:\" (RuntimeError)", "action"=>"webdav", "controller"=>"files", "raw_post_data"=>"<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<propfind>

    If you’ve got a chance to point me in the right direction, that’d be most appreciated!

  5. Stuart Eccles Says:

    Yes it does require the mime-types gem. I should put that in the documentation.

    That is an interesting error, looks like a problem with the properties getter maybe. Can you email me some info on which client you are testing it with and a full stack trace.

    thanks stueccles (at) gmail dot com

  6. Buzzed Says:

    How do i checkout the plugin? Seems to require a login. svn co http://svn.liverail.net/svn/plugins/railsdav ?

  7. Mat Says:

    This looks so promising, but I can’t get it working reliably. I’m curious though, why problems under webrick but okay under mongrel? Is there a Mongrel WebDAV implementation you’re relying on?

  8. Stuart Eccles Says:

    No it is not reliant on Mongrel it is entirely built with Ruby on Rails and should work fine in Lighttpd for instance.

    The WebBrick problems seem to be related to WebBrick handling PUT requests for large files. This could probably be solved by increasing the the cache size in WebBrick.

    Its still a first release and needs work but at the moment I just have zero time.

  9. patrick Says:

    Is there anything special to get it working with lighttpd?

    I got it working pretty well using mongrel in development, but when i switch to lighty, it just hangs when i try to mount a dav resource.

    thanks…looks great so far.

  10. Anthony Eden Says:

    Stuart,

    You rock. I am excited to be able to use Webdav directly from within Rails apps with your plugin. Thank you!

  11. Graham Says:

    Stuart – This looks great, thank you for putting this all together. I happened to be looking at Boxroom, any thoughts on how the two of these could play nicely together? Seems like this could be a really cheap/easy way to host a personal Strongspace type site. Is there any way to “intercept” files as they are uploaded/downloaded via WebDAV so that the proper “asset magic” could take place?

    Feel free to email or forward me on if that’s easier :)

    Cheers, Graham

  12. Graham Says:

    Stuart – This looks great, thank you for putting this all together. I happened to be looking at Boxroom, any thoughts on how the two of these could play nicely together? Seems like this could be a really cheap/easy way to host a personal Strongspace type site. Is there any way to “intercept” files as they are uploaded/downloaded via WebDAV so that the proper “asset magic” could take place?

    Feel free to email or forward me on if that’s easier :)

    Cheers, Graham

  13. Graham Says:

    Yikes…looks like my dropping connection messed up the post. Apologies.

  14. Sari Says:

    I am getting the error :

    Railsdav::WebDavController: missing default helper path railsdav/web_dav_helper Railsdav::FileSystem::FileWebDavController: missing default helper path railsdav/file_system/file_web_dav_helper MyStoreController: missing default helper path my_store_helper

    when I launch /mystore with mongrel

    Can anyone help? Thanks, Sari

  15. Sari Says:

    Got it working for downloading a single file. How do you configure things to work with a directory? WIthin the webdav root we created a test directory with a test file. We can pull the file if we put in the full pathname, but how do we display the directory contents.

    Thanks, Sari

  16. ligi Says:

    i have the same problem as railsdeveloper.com ( `typecast_xml_value’”,) – here some more infos:

    backtrace”=>[”/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_controller/cgi_ext/cgi_methods.rb:111:in `typecast_xml_value’”, ”/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_controller/cgi_ext/cgi_methods.rb:99:in `typecast_xml_value’”, ”/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:21:in `inject’”, ”/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_controller/cgi_ext/cgi_methods.rb:98:in `each’”, ”/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_controller/cgi_ext/cgi_methods.rb:98:in `inject’”, ”/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_controller/cgi_ext/cgi_methods.rb:98:in `typecast_xml_value’”, ”/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_controller/cgi_ext/cgi_methods.rb:99:in `typecast_xml_value’”, ”/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:21:in `inject’”, ”/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_controller/cgi_ext/cgi_methods.rb:98:in `each’”, ”/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_controller/cgi_ext/cgi_methods.rb:98:in `inject’”, ”/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_controller/cgi_ext/cgi_methods.rb:98:in `typecast_xml_value’”, ”/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_controller/cgi_ext/cgi_methods.rb:99:in `typecast_xml_value’”, ”/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:21:in `inject’”, ”/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_controller/cgi_ext/cgi_methods.rb:98:in `each’”, ”/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_controller/cgi_ext/cgi_methods.rb:98:in `inject’”, ”/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_controller/cgi_ext/cgi_methods.rb:98:in `typecast_xml_value’”, ”/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_controller/cgi_ext/cgi_methods.rb:99:in `typecast_xml_value’”, ”/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:21:in `inject’”, ”/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_controller/cgi_ext/cgi_methods.rb:98:in `each’”, ”/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_controller/cgi_ext/cgi_methods.rb:98:in `inject’”, ”/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_controller/cgi_ext/cgi_methods.rb:98:in `typecast_xml_value’”, ”/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_controller/cgi_ext/cgi_methods.rb:71:in `parse_formatted_request_parameters’”, ”/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_controller/cgi_process.rb:69:in `request_parameters’”, ”/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_controller/request.rb:13:in `parameters’”, ”/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_controller/session_management.rb:122:in `set_session_options_without_components’”, ”/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_controller/components.rb:178:in `set_session_options’”, ”/usr/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_controller/session_management.rb:116:in `process’”, ”/usr/lib/ruby/gems/1.8/gems/rails-1.1.6/lib/dispatcher.rb:38:in `dispatch’”, ”/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.3/lib/mongrel/rails.rb:73:in `process’”, ”/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.3/lib/mongrel.rb:551:in `process_client’”, ”/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.3/lib/mongrel.rb:550:in `each’”, ”/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.3/lib/mongrel.rb:550:in `process_client’”, ”/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.3/lib/mongrel.rb:636:in `run’”, ”/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.3/lib/mongrel.rb:636:in `initialize’”, ”/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.3/lib/mongrel.rb:636:in `new’”, ”/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.3/lib/mongrel.rb:636:in `run’”, ”/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.3/lib/mongrel.rb:625:in `initialize’”, ”/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.3/lib/mongrel.rb:625:in `new’”, ”/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.3/lib/mongrel.rb:625:in `run’”, ”/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.3/lib/mongrel.rb:956:in `run’”, ”/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.3/lib/mongrel.rb:955:in `each’”, ”/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.3/lib/mongrel.rb:955:in `run’”, ”/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.3/bin/mongrel_rails:127:in `run’”, ”/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.3/lib/mongrel/command.rb:199:in `run’”, ”/usr/lib/ruby/gems/1.8/gems/mongrel-0.3.13.3/bin/mongrel_rails:235”, ”/usr/bin/mongrel_rails:18:in `load’”, ”/usr/bin/mongrel_rails:18

    System Gentoo linunx / ruby 1.8.5 / rails 1.1.6 for more infos mailto: ruby -e ‘r=”” ; “FCMCjAKYSR\004NO”.each_byte {|b| r<<(b ^ 42) }; p r’

  17. ligi Says:
    copy and pasting failed and i cant edit the old entry – here the email adress again
    ruby -e  'r="" ; "FCMCjAKYSR\004NO".each_byte {|b| r<<(b ^ 42) }; p r'
    
  18. yegor Says:

    Hi Stuart, how difficult would it be to add some file path/name rewriting? Would it be enough to update santized_path or there are more places to change?

  19. Jan Says:

    I get the same error as Sari on 13 september 2006:

    Railsdav::WebDavController: missing default helper path railsdav/web_dav_helper Railsdav::FileSystem::FileWebDavController: missing default helper path railsdav/file_system/file_web_dav_helper MyStoreController: missing default helper path my_store_helper

    when I launch /mystore with mongrel

    He (Sari) did solve it, but I can’t … Can anyone help?

    Thanks, Jan

  20. Max Schuh Says:

    Hi,

    I get exactly the same error as jan and Sari. No solution yet?

    Thanks, Max

Sorry, comments are closed for this article.