MultiSite provides the ability to scope your models by tenant. MultiSite gem is very similar to multi-tenancy gems such as acts_as_tenant but less strict on it's implementation.
If you need to organize your models by site scope MultiSite is great for that!
gem 'multi_site'
- provides scopes to fetch records from a specific site
- give you helper methods know what is the current site
- keeps the switch site logic away from your application.
First, you need to have a class named Site. This is the only constraint you have.
class Site < ActiveRecord::Base
# ...
end
In your Models you need to insert the class method has_site_scope
to declare which ones
are scoped by site:
class User < ActiveRecord::Base
has_site_scope
end
class Card < ActiveRecord::Base
has_site_scope
end
Now on, every model registered has a new scope called on_site
.
When you call the model User with scope on_site
it should return all the users
from current site:
class UsersController < ApplicationController
def index
#fetch all the users
@all_users = User.all
#fetch all the users from current site
@site_users = User.on_site
#fetch all the users from current site with a certain age
@site_users = User.on_site.where(:age => 15)
end
end
Instead of scoping the classes to their tenants by default, MultiSite, allows the programmer to choose what he wants.
MultiSite provides a routing helper to to hide the site handling from you.
Application.routes.draw do
multi_site_scope do
resources :users
# this will handle a uri like this:
# /:multi_site/users/:id
# and you can use the route helpers transparently
# e.g. new_user_url, edit_user_path(1), etc
resources :cards
# /:multi_site/cards/...
end
end
All the resources inside of multi_site scope will automatically handle the multi_site
parameter, and all route helpers will use it transparently.
MultiSite provides a helper method called current_site
. It can be used on views or controllers
context and give us the current site selected by the application.
<% if current_site.present? %>
<p>Site Name: <%= current_site.name %></p>
<% else %>
<p> Please you need to <%= link_to "login", "/login" %> first.
<% end %>
MultiSite doesn't provide any security features. You have the responsability to implement them. For example, to guarantee that a user doesn't have access to unauthorized tenants, you can create a before_filter action that checks if the user's site is the same as current_site:
class UsersController < ApplicationController
before_filter :check_site_access
#...
def check_site_access
unless current_user.site == current_site
raise "Access Denied"
end
end
end
You'll surely need cross site operations. We can get you there providing a macro that allows site switching:
class Admin::AdminController < ApplicationController
cross_site_controller
def show
@admin_site = current_site
end
def switch_site
self.current_site = Site.find(params[:site_id])
redirect_to admin_admin_url, notice: "Switched to: #{current_site.url}"
end
end
you can declare the default site with:
MultiSite::Supra.default_site = Site.where(default: true).first
MultiSite uses thread context to keep current site id saved for scopes. If you initializate new threads you need to copy the current site to the new thread in order to keep the functionality unchanged.
For example:
site = current_site
Thread.new {
MultiSite.current_site = site
# .. do you work here
users = User.on_site
users.map {|u| u.simulate_taxes }
}
- make the site model name customizable
- make the param name entry customizable
- add specs for Rails 3+. Only Rails 4+ are provided at the moment
Copyright © 2013 Runtime Revolution, released under the MIT license.