Skip to content

motdotla/merb_auth_slice_multisite

Repository files navigation

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

About

Used by investapp.com. Add multisite/subdomain functionality to your merb app as a slice - includes login form, remember me, and forgot password functionality.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages