J'apprends à créer une application à locataires multiples dans Rails, qui sert les données de différents schémas en fonction du domaine ou du sous-domaine utilisé pour afficher l'application.
J'ai déjà quelques préoccupations répondues:
Ces trois points couvrent beaucoup de choses générales que je dois savoir. Cependant, dans les prochaines étapes, il me semble avoir de nombreuses façons de mettre en œuvre les choses. J'espère qu'il existe un moyen meilleur et plus facile.
Lorsqu'un nouvel utilisateur s'inscrit, je peux facilement créer le schéma. Cependant, quel serait le moyen le plus simple et le meilleur de charger la structure déjà présente dans le reste des schémas? Voici quelques questions/scénarios qui pourraient vous donner une meilleure idée.
Merci et j'espère que ça n'a pas été trop long!
Mise à jour du 5 décembre 2011
Merci à Brad Robertson et à son équipe, voici le Appartement gem . C'est très utile et soulage beaucoup de choses.
Cependant, si vous bricolez des schémas, je suggère fortement de savoir comment cela fonctionne réellement. Familiarisez-vous avec la procédure pas à pas de Jerod Santo , vous saurez ainsi ce que le joyau de l'appartement fait de plus ou moins.
Mise à jour du 20 août 2011 à 11h23 GMT + 8
Quelqu'un a créé un article blog et parcourt plutôt bien tout ce processus.
Mise à jour du 11 mai 2010 à 11h26 GMT + 8
Depuis la nuit dernière, j'ai pu utiliser une méthode qui crée un nouveau schéma et y charge schema.rb. Je ne sais pas si ce que je fais est correct (semble bien fonctionner jusqu'à présent), mais c'est un pas de plus au moins. S'il y a un meilleur moyen s'il vous plaît faites le moi savoir.
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
Changer la ligne 38 à:
conn.schema_search_path = "#{schema_name}, #{old_search_path}"
Je présume que postgres tente de rechercher les noms de tables existants lors du chargement de schema.rb et que vous avez défini le chemin search_path de manière à ne contenir que le nouveau schéma, il échoue. Bien entendu, cela suppose que vous avez toujours le schéma public dans votre base de données.
J'espère que cela pourra aider.
Y a-t-il un gem/plugin qui a 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
En outre, il prend soin de vider correctement les schémas dans le fichier schema.rb.