influitive / apartment

Database multi-tenancy for Rack (and Rails) applications
2.67k stars 460 forks source link

Question - migrations from another gem are failing #243

Open real-ashwin opened 9 years ago

real-ashwin commented 9 years ago

I have created a multi-tenant rails App using Apartment gem. I also have another gem in my application which has its own migrations.

I am facing an issue where that other gem’s migrations run and then fail because the tables already exist.

Here’s what I have done.

Created many tables.
rake db:migrate runs fine
Apartment::Tenant.create(‘new_tenant’)
//A new tenant is created and all the tables are created as expected

rails g model new_model name:string
rake db:migrate

This runs the migrations from the other gem and Postgres reports Table already exists and the migration fails for the previously created 'new_tenant'

Is this supposed to happen like this or did I break something in my setup?

bradrobertson commented 9 years ago

What's the other gem? The only thing I can think is that it is explicitly specifying a schema name along with a table name (which would be weird) but if you point me to their code I can try to see what's conflicting.

real-ashwin commented 9 years ago

The other gem is Payola

bradrobertson commented 9 years ago

Ok so I'm guessing you're tenanting the payola tables, so that each client gets its own set of payola data? My only guess is that migrating once will modify your schema.rb to include the payola tables. When you create a new tenant, it loads schema.rb into your new tenant which will include those tables, so they've already been created in the new tenant. When you run migrations, payola itself has modified the migration paths to include its own migrations, but I'm guessing that rails schema_migrations table doesn't actually know about these since they reside in the gem, thus it thinks it needs to run them again. That's why you get this error.

I can't actually think of a way around this, unless you can remove payola from the migrations path. See the code here where payola modifies the db/migrate paths to include its own. If you can somehow remove those in an initializer, I think that'd solve your problem.

real-ashwin commented 9 years ago

I tried both by tenanting and not tenanting the Payola tables. Thank you for taking the time to analyze this. I will try by searching for another gem which modifies the migrations path and if that fails too then will try removing them in an initializer. Thanks @bradrobertson .

real-ashwin commented 9 years ago

@bradrobertson After some debugging, I have figured out that the issue is because the schema_migrations table in the tenant does not contain all the versions. Copying the versions from public to tenants fixes the issue.

Apartment::Tenant.switch!("public")
SchemaMigration.all.count
36
Apartment::Tenant.switch!("tenant")
SchemaMigration.all.count
17
#19 versions from the gem are missing in tenant's schema_migrations.

Now, I copied versions from public to tenant.

Apartment::Tenant.switch!("public")
schemas = SchemaMigration.all

Apartment::Tenant.switch!("tenant")
schemas.each do |schema|
    migration = SchemaMigration.find_by_version(schema.version)
    if migration.nil?
        SchemaMigration.create(:version => schema.version)
    end
end

rake db:migrate passes now and I am able to create new models.

bradrobertson commented 9 years ago

Glad you got it sorted out.

real-ashwin commented 9 years ago

Do you know whom should I take this issue to, so that it gets fixed properly? Is it apartment, payola, rails or somebody else?

bradrobertson commented 9 years ago

It's unfortunately a combo of payloa/apartment. There's not really anything we can do to fix it, and I doubt payola would change their migration setup to accommodate us so it's kind of just an unfortunate situation.

real-ashwin commented 9 years ago

Thanks @bradrobertson

EminenceHC commented 8 years ago

+1 Did you ever figure out a better workaround @ashwinputhige ?

real-ashwin commented 8 years ago

Negative

On Jul 28, 2016 18:28, "EminenceHC" notifications@github.com wrote:

+1 Did you ever figure out a better workaround @ashwinputhige https://github.com/ashwinputhige ?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/influitive/apartment/issues/243#issuecomment-236071681, or mute the thread https://github.com/notifications/unsubscribe-auth/AG67LKb15jljDbyCw-lkKzqpcNsWPB4nks5qaVdFgaJpZM4FTGUW .

edave commented 6 years ago

One note to add to @ashwinputhige's answer above, is that I found I had to force schemas = SchemaMigration.all to an array, otherwise the .all() is lazily evaluated in the context of the Tenant's schema, which results in schemas being the Tenant's SchemaMigration.all and no new SchemaMigrations.

Here's an example of the code snippet that worked for me on Rails 4.2 and Apartment 1.2:

all_schema_migrations = []
tenant_id = my_new_tenant_id
Apartment::Tenant.switch ('public') do
  Apartment::Tenant.create(tenant_id)
  # Must purposefully force .all to an Array to load the public SchemaMigrations
  # otherwise, it is lazily evaluated in the context of the tenant's schema below
  # (which results in only the tenant's SchemaMigrations being loaded, instead of
  # public)
  all_schema_migrations = ActiveRecord::SchemaMigration.all.to_a
end

Apartment::Tenant.switch(tenant_id) do
  all_schema_migrations.each do |schema|
      migration = ActiveRecord::SchemaMigration.find_by_version(schema.version)
      if migration.nil? # It's missing, create it!
        ActiveRecord::SchemaMigration.create(:version => schema.version)
      end
  end
end