Advanced Rails 3 Tutorial Custom Resource, Devise, and User Specific Routing
In this advanced tutorial, we'll setup a Rails 3.1.x site that exposes user specific subdirectories with authentication through Devise.
There is a working example of this tutorial at: https://github.com/bryanrite/dav4rack-example-devise-subdirectories
This is a step by step walkthrough based on this: sample app.
To start, please follow the basic Rails 3 setup tutorial: https://github.com/chrisroberts/dav4rack/wiki/Rails-3
This will leave leave you with a Rails application that exposes the Rails root with no authentication.
Our first step is to create a custom resource for us to use. Within your app/models
directory, create a model for your WebDAV resources. In this example, we'll call it MyResource
:
# app/models/my_resource.rb
class MyResource < DAV4Rack::FileResource
end
Next, we want to use our new resource instead of the default Resource as were using in the Basic Rails 3 tutorial:
# config/routes.rb
mount DAV4Rack::Handler.new(
:root => Rails.root.to_s,
:root_uri_path => '/',
:resource_class => MyAppName::MyResource
), :at => '/', :constraints => { :subdomain => "webdav" }
Notice we changed the :resource_class
value to our new resource. If you start rails now (rails s
) and goto webdav.lvh.me:3000
(*.lvh.me is a convenient CNAME of localhost, good for working with subdomains on your development machine) in your WebDAV client, you should see your rails root directory. Great, we are now using our custom resource. Let's customize it.
We can add authentication with Devise quite simply. In this example, I'll work with the assumption that you're using Devise with usernames instead of email for its simplicity (http://railscasts.com/episodes/210-customizing-devise), but working with email should be fairly straight forward as well.
The use of the user
variable here is on purpose as this variable implemented in the parent class and automatically propagated to child files and directories.
We override the authentication method and ask Devise about valid users:
# app/model/my_resource.rb
...
private
def authenticate(username, password)
self.user = User.find_by_username(username)
user.try(:valid_password?, password)
end
You should now be able to connect or be denied access to WebDAV depending on your username/password.
A somewhat common setup is to host user files within named subdirectories. For example:
+ root_dir
|- username1
|- username2
|- username3
...
This also allows for chroot jails for ssh and ftp as well. So we want to expose this particular user's username as the WebDAV root, we can do this by overriding file root. Our updated resource file looks like:
# app/model/my_resource.rb
class MyResource < DAV4Rack::FileResource
def root
File.join(options[:root].to_s, user.username)
end
private
def authenticate(username, password)
self.user = User.find_by_username(username)
user.try(:valid_password?, password)
end
end
Now that we've chrooted the WebDAV client, we need to update our Rails routes with the proper root directory:
# config/routes.rb
mount DAV4Rack::Handler.new(
:root => "/path/to/root_dir/",
:root_uri_path => '/',
:resource_class => MyAppName::MyResource
), :at => '/', :constraints => { :subdomain => "webdav" }
Voila! Now, when you load up your WebDAV client, the root you are presented with should be root_dir/username
, securely segregating your client specific folders.
Thanks again to Chris for the great DAV4Rack!
Check out the sample app that has all of the above in a working Rails 3 app at: https://github.com/bryanrite/dav4rack-example-devise-subdirectories