Skip to content

Annotate should reset the cached information about columns #342

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 22, 2016

Conversation

akihiro17
Copy link
Contributor

Annotate should reset the cached information about columns because Annotate may output old information if we load ActiveRecord::Base class in migration files.

For example, if we have a following migration file and execute rake db:migrate, Annote does not output the default value and a not null constraint of the some_value column.

class CreatePosts < ActiveRecord::Migration
  def change
    create_table :posts do |t|
      t.integer :some_value
    end

    # add a not null constraint to the some_value column

    # should update some_value with not null values
    # because records might exist which have null value in the some_value column

    Post.update_all(some_value: 1)

    change_column_null(:posts, :some_value, false)
    change_column_default(:posts, :some_value, 1)
  end
end

This commit fixes the above issue.

before this commit

# == Schema Information
#
# Table name: posts
#
#  id         :integer          not null, primary key
#  some_value :integer
#

class Post < ActiveRecord::Base
end

after this commit

# == Schema Information
#
# Table name: posts
#
#  id         :integer          not null, primary key
#  some_value :integer          default(1), not null
#

class Post < ActiveRecord::Base
end

Annotate should reset the cached information about columns because Annotate may output old information if we load ActiveRecord::Base class in migration files.

For example, if we have a following migration file and execute 'rake db:migrate', Annote does not output the default value and a not null constraint of the `some_value` column.

```ruby
class CreatePosts < ActiveRecord::Migration
  def change
    create_table :posts do |t|
      t.integer :some_value
    end

    # add a not null constraint to the some_value column

    # should update some_value with not null values
    # because records might exist which have null value in the some_value column

    Post.update_all(some_value: 1)

    change_column_null(:posts, :some_value, false)
    change_column_default(:posts, :some_value, 1)
  end
end
```

This commit fixes the above issue.
@b264
Copy link
Contributor

b264 commented Feb 11, 2016

If you reference an ActiveRecord::Base class in migration files, you are introducing a time-travel problem in your migration. The model code can change, and if your migration is run in the future, say, when a new developer joins or when someone gets a new computer, then it may not work as designed with whatever the new code is. See https://github.com/testdouble/good-migrations I have run into very nasty problems stemming from this in legacy migrations, and I recommend using an SQL statement for the update, YMMV

@ctran
Copy link
Owner

ctran commented Feb 12, 2016

That's sound advice. @akihiro17, If you re-run migrate, does it fix the annotations (without the suggested fix)?

@akihiro17
Copy link
Contributor Author

@b264

Thank you for your advice. I've figured out it's not a good idea to access ActiveRecord model objects defined in app/models in migrations.

@ctran

  1. redefine the class inside the migration(without this PR)

    does not work as expected because the SchemaCache caches column information for the posts table.

class CreatePosts < ActiveRecord::Migration
  class PostInMigration < ActiveRecord::Base
    self.table_name = :posts
  end

  def change
----
    # should update some_value with not null values
    # because records might exist which have null value in the some_value column
    PostInMigration.update_all(some_value: 1)
---
  end
end
  1. use an SQL statement(without this PR)

    works as expected because ActiveRecord does not cache the column information.

class CreatePosts < ActiveRecord::Migration
  def change
---
    # should update some_value with not null values
    # because records might exist which have null value in the some_value column
    execute('update posts set some_value = 1')
---   
  end
end

Thank you.

@ctran ctran merged commit e84f1f3 into ctran:develop Apr 22, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants