public
Description: Used by investapp.com. Add multisite/subdomain functionality to your merb app as a slice - includes login form, remember me, and forgot password functionality.
Homepage: http://investapp.com
Clone URL: git://github.com/scottmotte/merb_auth_slice_multisite.git
name age message
file .document Fri Mar 27 13:26:16 -0700 2009 Initial commit to merb_auth_slice_multisite. [scottmotte]
file .gitignore Fri Mar 27 17:57:33 -0700 2009 Go ahead and get the bin in there [scottmotte]
file LICENSE Fri Mar 27 15:01:02 -0700 2009 License change [scottmotte]
file README.textile Sun May 03 11:51:59 -0700 2009 remember me functionality thanks to rughetto [scottmotte]
file Rakefile Fri Mar 27 18:58:19 -0700 2009 Add app, config,public, and stubs to gemspec [scottmotte]
file VERSION.yml Sat May 09 18:18:22 -0700 2009 Version bump to 0.8.6 [scottmotte]
directory app/ Mon May 04 09:11:01 -0700 2009 Fix remember me label [scottmotte]
directory config/ Sat May 09 13:50:29 -0700 2009 Fixes remember me functionality. Need tests to ... [scottmotte]
directory lib/ Sat May 09 15:01:07 -0700 2009 Compare time to time or otherwise error [scottmotte]
file merb_auth_slice_multisite.gemspec Sat May 09 18:18:26 -0700 2009 Regenerated gemspec for version 0.8.6 [scottmotte]
directory public/ Fri Mar 27 13:31:13 -0700 2009 Add the stuff from a blank slice [scottmotte]
directory spec/ Sat May 09 13:50:29 -0700 2009 Fixes remember me functionality. Need tests to ... [scottmotte]
directory stubs/ Sat May 09 18:18:10 -0700 2009 Add a stub for the login form [scottmotte]
README.textile

MerbAuthSliceMultisite

This slice setups multisite capabilities in your merb application with subdomains (i.e. coolcars.yourapp.com) and an authentication check.

Noteworthy: This multisite gem validates the usernames by the scope of the subdomain. This means someone can create another subdomain site using the same username and password, but technically it will be a new user in the users table – similar to how blinksale works. This is how I prefer things. It saves the hassle of a has_and_belongs_to_many relationship and the extra signup hoops you have to go through as a user if you want to create multiple accounts – lighthouse is an example of this.

Instructions for installation:

1. Add github as a gem source & install

gem sources -a http://gems.github.com
sudo gem install scottmotte-merb_auth_slice_multisite

2. Setup your application to use the gem.* Add the following to the end of dependencies.rb.

dependency "scottmotte-merb_auth_slice_multisite", :require_as => 'merb_auth_slice_multisite'

3. Remove default merb-auth-slice-password in dependencies.rb

dependency “merb-auth-slice-password”

(merb_auth_slice_multisite is now standalone. it does not depend on merb-auth-slice-password)

4. Add in mixin. In your user model or in merb/merb-auth/setup.rb add the mixin
include Merb::Authentication::Mixins::UserBelongsToSite and then migrate your database.

  1. in model
    class User
    include Merb::Authentication::Mixins::UserBelongsToSite
    include Merb::Authentication::Mixins::AuthenticatedUser #for remember me functionality
    end
  1. or as I prefer in merb/merb-auth/setup.rb
    Merb::Authentication.user_class.class_eval{
    include Merb::Authentication::Mixins::SaltedUser
    include Merb::Authentication::Mixins::ActivatedUser
    include Merb::Authentication::Mixins::UserBelongsToSite # <— this one
    include Merb::Authentication::Mixins::AuthenticatedUser # <— and this one
    }

Don’t forget to migrate your database schema with rake db:autoupgrade or rake db:automigrate

5. Setup strategies.rb – make sure it looks like the following. merb_auth_slice_multisite uses its own custom strategy so including the others will mess things up.

Merb::Slices::config[:"merb_auth_slice_multisite"][:no_default_strategies] = false

As an aside, here’s what an example router might look like using the slice to support subdomains. See how it checks for subdomain equaling www or nil and routes to the main site. And then everything else goes to the pages controller or users controller that has a subdomain. All of the controller actions then user @current_site.pages.all and @current_site.users.all instead of just User.all & Page.all. Starting to come together in your mind :)


	Merb.logger.info("Compiling routes...")
	Merb::Router.prepare do

	  # Brochure site - equal to site_url from settings.yml and has no first_subdomain else do below
	  match(:first_subdomain =>  /^(www)*$/) do
	    resources :sites, :collection => { :changed_on_spreedly => :post }
	    resources :static
	    match('/signup').to(:controller => 'sites', :action => 'new')
	    match('/').to(:controller => 'static', :action => 'index')
	  end

	  # Subdomain sites
	  resources :pages
	  resources :users, :identify => :login

	  match('/').to(:controller => 'pages', :action => 'index')
	  slice(:merb_auth_slice_multisite, :name_prefix => nil, :path_prefix => "") # /login, /logout
	end

6. Add the slice’s routes to your router

slice(:merb_auth_slice_multisite, :name_prefix => nil, :path_prefix => "")

7. Setup @current_site value. I haven’t worked out how to make it automatically accessible yet so for now paste the following into your app’s application.rb file.


before :get_site
def get_site

  1. uses @current_site – for example, to create pages under current site do @current_site.pages.new
    @current_site = Site.first(:subdomain => request.first_subdomain)
    raise NotFound unless @current_site
    end

8. Configure forgot_password functionality. Add the following into merb/merb-auth/setup.rb

# To change the parameter names for the password or login field you may set either of these two options
#

  1. Merb::Plugins.config[:“merb-auth”][:login_param] = :email
  2. Merb::Plugins.config[:“merb-auth”][:password_param] = :my_password_field_name
    Merb::Slices::config[:merb_auth_slice_multisite][:send_password_from_email] = “no-reply@yourapp.com”
    Merb::Slices::config[:merb_auth_slice_multisite][:domain] = “example.com”

Additional details:

Schema/Migrations. The mixin adds some fields to your user model. Where needed include these in your migrations if you are using migrations.

# Relationships/Associations
belongs_to :site
property :site_id, Integer
validates_is_unique :login, :scope => :site_id
validates_is_unique :email, :scope => :site_id

Site model. You’re probably wondering where the heck is the site model. It’s in the slice. You can override it by running one of the rake tasks or you can create your own site.rb model and add additional fields which is what I do. For example, if you have pages under a site, you might do something like:

# site.rb
class Site
  has n, :pages, :order => [:position.asc]
end

@current_site. You can use @current_site in your controllers like so:


class Pages < Application

  1. provides :xml, :yaml, :js
def index @pages = @current_site.pages.all display @pages end def show(id) @page = @current_site.pages.get(id) raise NotFound unless @page display @page end

end # Pages

Assumptions

  • works for subdomains (i.e. coolcars.yourapp.com)
  • merb only
  • merb-auth-core dependency
  • merb-auth-more dependency
  • only supports datamapper so far (help me extend it! fork the project and request me to pull)
  • A site has n (has_many) users. A user belongs_to a site.
  • You can have multiple users with the same username and password as long as they each belong_to a different site. For example, there can be an admin user with the credentials { :login => ‘admin’, :email => ‘admin@example.org’, :site_id => 1} and an admin user with the credentials { :login => ‘admin’, :email => ‘admin@example.org’, :site_id => 66}. As long as the site_id is different then it is ok. This allows more freedom when your users want to setup multiple sites.

How does it work?

When logging in the “user” object found by merb-auth-core will be asked whether the user’s login, password, and site_id match. It matches the site_id against the @current_site.id, and the login/password from the standard form fields.

Rake tasks

To see all available tasks for MerbAuthSliceMultisite run:

rake -T slices:merb_auth_slice_multisite