Writing a multi-tenant Rails 3 app for deployment on Heroku

后端 未结 3 1801
南旧
南旧 2020-12-23 23:27

I\'m building a Rails 3 app for deployment on Heroku, and I\'m wondering if there are any recommendations on how to handle multi-tenancy in my models. Half a year ago, ther

相关标签:
3条回答
  • 2020-12-23 23:47

    I am about to embark on this venture(implementing multi-tenancy for a small rails app) and while doing research I stumbled on this SO post.

    It is surprising that no one mentioned about the great screencast by RyanB on implementing MT using PostgreSQL schemas which is supported by Heroku.

    Here is the link to the screencast http://railscasts.com/episodes/389-multitenancy-with-postgresql.

    Concept:

    In rails app,we can set a search path for pg connection

          connection.schema_search_path = "schema1, schema2, ..."
    

    any subsequent actions will be executed on schema1 if it finds the corresponding table there. Otherwise, it searches for the table in schema2 and so on. To being with your entire app schema including tenant will be in public and usual practice is to make all the tables except tenant empty in public schema.

    New Tenant Registration:

    Add an after_create function to your Tenant model to create a new schema for the new tenant and create all (load schema.rb) app tables (except Tenant) into this new schema.

    User:

    when a user visits, subdomain1.myapp.com, find the schema for this subdomain from tenant table and set the connection search path to 'schema1, public' and authenticate the user.

    Please note, my intention is just to cover the concept behind the solution. Refer to RyanB's screencast for the actual solution.

    0 讨论(0)
  • 2020-12-23 23:55

    The approaches range from "share nothing", which usually means one database per tenant, to "share everything", which usually means each table contains rows from many tenants. The spectrum (below) can be broken down by degree of isolation, by cost (cost per tenant, that is), and by ease of disaster recovery.

    • One database per tenant; highest cost, highest isolation, easiest recovery.
    • One schema per tenant; cost between the other two, good isolation, fairly easy recovery, but recovery usually degrades performance for other tenants.
    • Share tables among tenants; lowest cost, lowest isolation (shared tables), difficult disaster recovery (recovery usually means recovering some rows for every table). Recovery usually degrades performance "a lot" for the other tenants.

    All those are platform-specific to some degree. "One database per tenant" has the highest isolation when the dbms prohibits queries from accessing more than one database. But some platforms allow querying across multiple databases.

    MSDN has a decent article that hits the high points: Multi-Tenant Data Architecture.

    But if you're limited to Heroku, you'll have to pick an option that Heroku supports. I don't know what those options might be, but I do know that you're better off not using SQLite in development. Heroku deployments are going to run on PostgreSQL; you need to develop against PostgreSQL.

    0 讨论(0)
  • 2020-12-24 00:10

    As the author of the multitenant gem, I'm obviously biased, but I really believe that it is a great solution! The goal of the gem is to simplify this common application need and make it trivial to implement.

    The "old school" alternative is to use rails object chaining to ensure that all queries are done through the associated parent. The issue with this approach is that your Tenant object becomes a dumping ground for has_many associations.

    class Tenant
      has_many :users
    end
    # query for users in the current tenant
    current_tenant.users.find params[:id]
    

    The multitenant gem solves this by ensuring that all queries generated are automatically aware of the current tenant. And it also ensures that new records are created and automatically assigned to the current tenant so you don't need to add any special before_save callbacks.

    ex:

    Multitenant.with_tenant current_tenant do
      # queries within this block are automatically
      # scoped to the current tenant
      User.all
    
      # records created within this block are
      # automatically assigned to the current tenant
      User.create :name => 'Bob'
    end
    
    0 讨论(0)
提交回复
热议问题