ruby-on-rails - proyecto - rails new myapp postgresql
Crear una aplicaciĆ³n multi-tenant utilizando esquemas y rieles de PostgreSQL (3)
Cosas que ya he descifrado
Estoy aprendiendo cómo crear una aplicación multi-tenant en Rails que sirve datos de diferentes esquemas en función de qué dominio o subdominio se utiliza para ver la aplicación.
Ya tengo algunas inquietudes respondidas:
- ¿Cómo se puede hacer que subdomain-fu también funcione con dominios? Aquí hay alguien que hizo la misma pregunta que te lleva a este blog .
- ¿Qué base de datos y cómo se estructurará? Aquí hay una excelente charla de Guy Naor , y una buena pregunta sobre PostgreSQL y esquemas .
- Ya sé que mis esquemas tendrán la misma estructura. Diferirán en la información que guardan. Entonces, ¿cómo se pueden ejecutar migraciones para todos los esquemas? Aquí hay una respuesta .
Esos tres puntos cubren muchas de las cosas generales que necesito saber. Sin embargo, en los siguientes pasos parece que tengo muchas formas de implementar las cosas. Espero que haya una manera mejor y más fácil.
Finalmente, a mi pregunta
Cuando un nuevo usuario se registra, puedo crear el esquema fácilmente. Sin embargo, ¿cuál sería la mejor y más fácil forma de cargar la estructura que el resto de los esquemas ya tienen? Aquí hay algunas preguntas / escenarios que pueden darle una mejor idea.
- ¿Debería pasarlo a un script de shell que vuelque el esquema público en uno temporal y lo vuelva a importar a mi base de datos principal (más o menos como dice Guy Naor en su video)? Aquí hay un resumen / script rápido que obtuve del #postgres útil en freenode . Si bien esto probablemente funcionará, tendré que hacer muchas cosas fuera de Rails, lo que me incomoda un poco ... lo que también me lleva a la siguiente pregunta.
- ¿Hay alguna manera de hacer esto directamente desde Ruby on Rails ? Al igual que crear un esquema de PostgreSQL, simplemente cargue el esquema de la base de datos de Rails (schema.rb, lo sé, es confuso) en ese esquema de PostgreSQL.
- ¿Hay alguna joya / complemento que ya tenga estas cosas? Métodos como "create_pg_schema_and_load_rails_schema (the_new_schema_name)". Si no hay ninguno, probablemente trabaje para hacer uno, pero dudo sobre lo bien probado que será con todas las partes móviles (especialmente si termino usando un script de shell para crear y administrar nuevos esquemas de PostgreSQL).
Gracias, y espero que no sea demasiado largo!
¿Hay alguna joya / complemento que ya tenga estas cosas?
pg_power proporciona esta funcionalidad para crear / eliminar esquemas PostgreSQL en la migración, como este:
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
También se ocupa de eliminar correctamente los esquemas en el archivo schema.rb.
Cambiar la línea 38 a:
conn.schema_search_path = "#{schema_name}, #{old_search_path}"
Supongo que postgres está intentando buscar nombres de tabla existentes al cargar schema.rb y, dado que ha establecido que search_path solo contenga el nuevo esquema, falla. Esto, por supuesto, supone que todavía tiene el esquema público en su base de datos.
Espero que ayude.
Actualización 5 de diciembre de 2011
Gracias a Brad Robertson y su equipo, está la joya de Apartamento . Es muy útil y hace mucho trabajo pesado.
Sin embargo, si está jugando con los esquemas, le sugiero que sepa cómo funciona realmente. Familiarízate con la guía de Jerod Santo , para que sepas qué hace la gema del Apartamento más o menos.
Actualización 20 de agosto de 2011 11:23 GMT + 8
Alguien creó una publicación de blog y recorre todo este proceso bastante bien.
Actualización 11 de mayo de 2010 11:26 GMT + 8
Desde anoche pude obtener un método para trabajar que crea un nuevo esquema y carga schema.rb en él. No estoy seguro de si lo que estoy haciendo es correcto (parece funcionar bien, hasta ahora) pero al menos está un paso más cerca. Si hay una mejor manera, por favor avíseme.
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