Création d'une application multi-locataires utilisant les schémas et les Rails de PostgreSQL

Trucs que j'ai déjà compris

j'apprends comment créer une application multi-locataires dans les Rails qui sert des données de différents schémas basés sur quel domaine ou sous-domaine est utilisé pour voir l'application.

j'ai déjà quelques préoccupations répondues:

  1. Comment faire fonctionner subdomain-fu avec des domaines? voici quelqu'un qui a posé la même question qui vous mène à ce blog .
  2. quelle base de données, et comment sera-t-elle structurée? Voici un excellent parler par Guy Naor , et bien question à propos de PostgreSQL et de schémas .
  3. je sais déjà que mes schémas auront tous la même structure. Ils diffèrent dans les données qu'ils détiennent. Donc, Comment Pouvez-vous exécuter des migrations pour tous les schémas? an an an answer .

ces trois points couvrent beaucoup de choses générales que j'ai besoin de savoir. Toutefois, dans les prochaines étapes, il me semble que j'ai de nombreuses façons de mettre les choses en œuvre. J'espère qu'il y a une meilleure, la plus facile.

enfin, à ma question

quand un nouvel utilisateur s'inscrit, je peux facilement créer le schéma. Cependant, quelle serait la meilleure et la plus facile façon de charger la structure que le reste des schémas déjà? Voici quelques questions/scénarios qui pourraient vous donner une meilleure idée.

  1. devrais-je le transmettre à un shell script qui jette le schéma public dans un temporaire, et l'importe de nouveau à ma base de données principale (à peu près comme ce que Guy Naor dit dans sa vidéo)? Voici un résumé rapide/script que j'ai reçu de l'utile #postgres sur freenode . Bien que ce sera probablement je vais devoir faire plein de choses en dehors des Rails, ce qui me met un peu mal à l'aise.. ce qui m'amène à la question suivante.
  2. y a-t-il un moyen de le faire directement à partir de Ruby sur les Rails ? Comme créer un schéma PostgreSQL, puis Charger le schéma de la base de données Rails (schéma.rb - je sais, c'est source de confusion) dans PostgreSQL schéma.
  3. y a-t-il un gem/plugin qui possède déjà ces choses? Des méthodes comme"create_pg_schema_and_load_rails_schema(the_new_schema_name)". S'il n'y en a pas, je travaillerai probablement à en faire un, mais je doute qu'il soit bien testé avec toutes les pièces mobiles (surtout si je finis par utiliser un script shell pour créer et gérer de nouveaux schémas PostgreSQL).

Merci, et j'espère que ce n'était pas trop long!

45
demandé sur Community 2010-05-06 20:37:51

3 réponses

Mettre À Jour Le 5 Décembre 2011

grâce à Brad Robertson et son équipe, il y a le Appartement gem . Il est très utile et fait beaucoup de levage lourd.

cependant, si vous devez bricoler des schémas, je suggère fortement de savoir comment cela fonctionne réellement. Familiarisez-vous avec Jerod Santo's walkthrough , de sorte que vous saurez ce que le joyau de L'appartement est plus ou moins de faire.

Update Aug 20, 2011 11: 23 GMT+8

Quelqu'un a créé un blog post et marche à travers tout ce processus assez bien.

Update May 11, 2010 11:26 GMT+8

depuis hier soir, j'ai pu obtenir une méthode de travail qui crée un nouveau schéma et charge le schéma.rb. Je ne sais pas si ce que je fais est correct (semble fonctionner bien, jusqu'à présent), mais c'est une étape de plus au moins. S'il y a un meilleur moyen, dites-le-moi.


  module SchemaUtils
   def self.add_schema_to_path(schema)
    conn = ActiveRecord::Base.connection
    conn.execute "SET search_path TO #{schema}, #{conn.schema_search_path}"
   end

   def self.reset_search_path
    conn = ActiveRecord::Base.connection
    conn.execute "SET search_path TO #{conn.schema_search_path}"
   end

   def self.create_and_migrate_schema(schema_name)
    conn = ActiveRecord::Base.connection

    schemas = conn.select_values("select * from pg_namespace where nspname != 'information_schema' AND nspname NOT LIKE 'pg%'")

    if schemas.include?(schema_name)
     tables = conn.tables
     Rails.logger.info "#{schema_name} exists already with these tables #{tables.inspect}"
    else
     Rails.logger.info "About to create #{schema_name}"
     conn.execute "create schema #{schema_name}"
    end

    # Save the old search path so we can set it back at the end of this method
    old_search_path = conn.schema_search_path

    # Tried to set the search path like in the methods above (from Guy Naor)
    # [METHOD 1]: conn.execute "SET search_path TO #{schema_name}"
    # But the connection itself seems to remember the old search path.
    # When Rails executes a schema it first asks if the table it will load in already exists and if :force => true. 
    # If both true, it will drop the table and then load it. 
    # The problem is that in the METHOD 1 way of setting things, ActiveRecord::Base.connection.schema_search_path still returns $user,public.
    # That means that when Rails tries to load the schema, and asks if the tables exist, it searches for these tables in the public schema.
    # See line 655 in Rails 2.3.5 activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
    # That's why I kept running into this error of the table existing when it didn't (in the newly created schema).
    # If used this way [METHOD 2], it works. ActiveRecord::Base.connection.schema_search_path returns the string we pass it.
    conn.schema_search_path = schema_name

    # Directly from databases.rake. 
    # In Rails 2.3.5 databases.rake can be found in railties/lib/tasks/databases.rake
    file = "#{Rails.root}/db/schema.rb"
    if File.exists?(file)
     Rails.logger.info "About to load the schema #{file}"
     load(file)
    else
     abort %{#{file} doesn't exist yet. It's possible that you just ran a migration!}
    end

    Rails.logger.info "About to set search path back to #{old_search_path}."
    conn.schema_search_path = old_search_path
   end
  end
12
répondu Ramon Tayag 2013-09-03 17:42:46

changer la ligne 38 en:

conn.schema_search_path = "#{schema_name}, #{old_search_path}"

je présume que postgres essaye de rechercher les noms de table existants lors du chargement du schéma.rb et puisque vous avez défini le search_path pour contenir uniquement le nouveau schéma, il échoue. Ceci, bien sûr, suppose que vous avez encore le schéma public dans votre base de données.

Espère que ça aide.

3
répondu Brendan Hay 2011-03-18 08:52:59

y a-t-il un gem/plugin qui possède déjà ces choses?

pg_power fournit cette fonctionnalité pour créer/supprimer des schémas PostgreSQL dans la migration, comme ceci:

def change
  # Create schema
  create_schema 'demography'

  # Create new table in specific schema
  create_table "countries", :schema => "demography" do |t|
    # columns goes here
  end

  # Drop schema
  drop_schema 'politics'
end

aussi il prend soin de correctement décharger les schémas dans le schéma.dossier rb.

0
répondu Sergey Potapov 2013-08-14 09:32:09