hzamani / acts_as_relation

Multi table Inheritance for rails
http://hzamani.github.com/acts_as_relation/
MIT License
180 stars 58 forks source link

Circular reference issue when running migration #59

Closed dzoltok closed 10 years ago

dzoltok commented 10 years ago

I sure hope someone else has this problem!

We've been using this gem for several months to provide common functionality to several of our models without having lots of duplicated data and empty tables, but we encountered a problem when we first tried adding the table for the common parent table. Namely, when trying to add our parent model (TaggedObject) to the database by running

rake db:migrate

we get an error saying that the table 'tagged_objects' doesn't exist. It seems like this is because Rails loads the entire environment before it runs migrations. But the environment includes models with acts_as :tagged_object, which expects the tagged_objects table to already exist! So the model requires the table, but creating the table requires the model, which requires the table, and so on.

We got around this issue at first by patching our code to not reference acts_as, running the migrations, then un-patching. But now that we're ramping up our servers that's not a maintainable solution anymore. Does anyone have an idea of how to avoid this problem?

BattleBrisket commented 10 years ago

You might be able to avoid the error you're seeing by creating dummy local models within the migration, matching the old and new model names.

class CreateTaggedObjects << ActiveRecord::Migration

  class TaggedObject << ActiveRecord::Base; end
  class TaggedObjectChild << ActiveRecord::Base; end

  def change
    create_table :tagged_objects do |t|
      # usual stuff here
    end
  end

end

It's worth mentioning that this is an order-of-operations issue: you are creating models for tables which don't exist yet. This is not isolated to the acts_as_relation gem, and can creep up with other complex Rails configurations. Even renaming a table can cause the same problem.

Even if the structure is still in flux, you should at least generate a migration that creates the table. You just need a placeholder, Rails shouldn't complain after that.

To avoid that landmine when I am laying out my models, I generally follow a 2-step dance:

  1. Run rails g model to give me a model and accompanying migration
  2. Run rails g migration to make any modifications to the table created in Step 1.

This only works if your Rails generator configuration is set up to create migrations along with models, so double check for setting changes to config.generators in config/application.rb.

hzamani commented 10 years ago

Thanks to @BattleBrisket

BattleBrisket commented 10 years ago

Happy to help @hzamani !