Question

I'm adding a counter_cache, and my migrate is getting an error.

def up
    add_column :benefits, :benefit_rows_count, :integer, :default => 0

    Benefit.reset_column_information
    Benefit.find(:all).each do |b|
      Benefit.update_counters b.id, :benefit_rows_count => b.benefit_rows.length
    end
end

SQL:

UPDATE "benefits" SET "benefit_rows_count" = COALESCE("benefit_rows_count", 0) + 0 
WHERE "benefits"."id" IN (SELECT "benefits"."id" 
    FROM "benefits"
    WHERE "benefits"."id" = 1 
    ORDER BY benefit_types.position, benefit_types.name, id)

This ORDER BY, inside the update is because of the default_scope, and it fails the migration.

Unfortunately, when i update the record, i get the same error when the callback update_counters is executed. I've read some posts that said default_scope should be avoided. I checked Rails 4 source code (i'm using Rails 3) and update_counters has not been fixed. I'm going to reopen ActiveRecord::CounterCache.update_counters and try to unscope it.

Was it helpful?

Solution

As already noted, your default scopes are tripping you up. There's a better way to avoid this sort of issue in your migrations: redefine your model in the scope of the migration:

class MigrateFooToBar < ActiveRecord::Migration

  class Foo < ActiveRecord::Base; end

  def up
    # ...
  end
end

When you then reference Foo from within up you reference the void-of-restrictions-and-default-scopes MigrateFooToBar::Foo which keeps you migrations from A) having to know too much about your models and B) confusing everybody else on your team when they run your migrations.

OTHER TIPS

Thx Baldrick, i'm new to rails. And unscoped worked:

Benefit.unscoped.update_counters b.id, :benefit_rows_count => b.benefit_rows.length
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top