Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Failing test case for values not persisting after add_column #6702

Closed
wants to merge 1 commit into from

5 participants

@jdelStrother

Given a migration like

  puts Post.inspect
  add_column :posts, :body, :string
  Post.find_each do |p|
    p.body = 'foo'
    p.save!
  end

both the assignment to 'body' and the save will succeed, but the value isn't written into the database, and you're left with nil values for 'body'.

(Obviously the "puts Post.inspect" is artificial - in our case, I think a plugin is loading our models prematurely, and so ActiveRecord caches the pre-migration column information)

The attached (failing) test checks that the new column's value is persisted properly. Perhaps this could be achieved by implicitly calling reset_column_information after each schema change. However, I don't care too much about that behaviour - I'd be just as happy with getting NoMethodError on trying to assign to 'body'. We were caught out and lost some production data because the model update appeared to work fine, when it was actually just dropping the values assigned to it.

See #6679 for prior discussion.

@jdelStrother jdelStrother Failing test case for values not persisting after add_column
Given a migration like

  add_column :posts, :body, :string
  Post.find_each do |p|
    p.body = 'foo'
    p.save!
  end


both the assignment to 'body' and the save will succeed, but the value isn't written into the database, and you're left with nil values for 'body'.

Perhaps add_column should implicitly call reset_column_information?  Having the 'body' accessor raise NoMethodError instead of appearing to succeed would also be fine...
f6bf26b
@josevalim
Owner

I think @jonleighton has some plans for not allowing .body to work. Calling reset_column_information would also be possible, since AR already tracks its descendants.

@parndt

Is it generally advised to assign values in a migration? Given that there's an acceptable workaround of reset_column_information is this an issue that needs solving?

@senny
Owner

I agree with @parndt. This is not necessarily an issue we need to solve. In general using your models in your migrations leads to problems of some sort. If you absolutely have to you can use the workaround.

@rafaelfranca @carlosantoniodasilva thoughts?

@rafaelfranca

I agree. Actually I always advice to never change data in migrations

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jun 11, 2012
  1. @jdelStrother

    Failing test case for values not persisting after add_column

    jdelStrother authored
    Given a migration like
    
      add_column :posts, :body, :string
      Post.find_each do |p|
        p.body = 'foo'
        p.save!
      end
    
    
    both the assignment to 'body' and the save will succeed, but the value isn't written into the database, and you're left with nil values for 'body'.
    
    Perhaps add_column should implicitly call reset_column_information?  Having the 'body' accessor raise NoMethodError instead of appearing to succeed would also be fine...
This page is out of date. Refresh to see the latest.
Showing with 21 additions and 0 deletions.
  1. +21 −0 activerecord/test/cases/migration/change_schema_test.rb
View
21 activerecord/test/cases/migration/change_schema_test.rb
@@ -311,6 +311,27 @@ def test_column_exists_on_table_with_no_options_parameter_supplied
end
end
+ def test_add_column_persists_values
+ connection.create_table :testings do |t|
+ t.column :title, :string
+ end
+ person_klass = Class.new(ActiveRecord::Base)
+ person_klass.table_name = 'testings'
+ 2.times do
+ person_klass.create!(title:'foo')
+ end
+
+ person_klass.connection.add_column 'testings', 'body', :text
+ person_klass.find_each do |person|
+ person.body = 'Ba Ba Black Sheep'
+ person.save!
+ end
+
+ person_klass.find_each do |person|
+ assert_equal 'Ba Ba Black Sheep', person.body
+ end
+ end
+
private
def testing_table_with_only_foo_attribute
connection.create_table :testings, :id => false do |t|
Something went wrong with that request. Please try again.