在我的Rails DB上运行迁移,安静地添加列并随机删除表而没有控制台错误

时间:2015-08-07 20:07:04

标签: ruby-on-rails ruby sqlite migration schema

我只能通过慢慢地完成迁移来解决这个问题。在过去的两天里,我一直在尝试做一些简单的事情。从我的verdict:text表格中删除一列simulations,然后添加另一列:opinions:hash

这样做会导致各种错误,例如没有方法'my_sym',并且说模拟表不存在。

我最初认为我通过这样做解决了这个问题:

rake db:drop
rake db:schema:dump
rake db:migrate VERSION="<Migration1>"
rake db:migrate VERSION="<Migration2>"
rake db:setup ENV="test"

迁移1:

class DeviseCreateUsers < ActiveRecord::Migration
  def change
    create_table(:users) do |t|
      ## Database authenticatable
      t.string :email,              :null => false, :default => "", limit: 96
      t.string :encrypted_password, :null => false, :default => "", limit: 60

      t.timestamps

      t.index :email, unique: true
    end
  end
end

迁移2:

class CreateSimulations < ActiveRecord::Migration
  def change
    # Needs the hash column worked out before this is run 
    create_table :simulations do |t|
        t.integer :x_size
        t.integer :y_size
        t.string :verdict
        t.string :arrangement 
    end

    add_reference :simulations, :user, index: true    
  end
end

这让我回到了原点(我的所有测试工作似乎都处于我开始遇到问题之前的初始状态),所以我重新编写了两个令人不快的迁移,认为它们可能是问题,运行了两个按此顺序迁移(我删除了列,然后添加了另一个,与我之前尝试的相反的顺序,想到可能订单有一些效果)。

迁移3:

class RemoveVerdictFromSimulation < ActiveRecord::Migration
  def change
    remove_column :simulations, :verdict, :string
  end
end

迁移4:

class AddOpinionToSimulations < ActiveRecord::Migration
  def change
    add_column :simulations, :opinion, :hash
  end
end

编辑:经过进一步调查,第4次迁移导致了模拟表无故障的问题。

这些迁移均可正常运行。但是我知道做其他事情会导致错误(例如运行rspec),因为看起来问题是这些迁移之一会导致schema.rb文件出错。

运行这些最后一次迁移3&amp; 4后,我之前同时拥有用户和模拟表的schema.rb如下所示:

ActiveRecord::Schema.define(version: 20150807193122) do

# Could not dump table "simulations" because of following NoMethodError
#   undefined method `[]' for nil:NilClass

  create_table "users", force: :cascade do |t|
    t.string   "email",              limit: 96, default: "", null: false
    t.string   "encrypted_password", limit: 60, default: "", null: false
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  add_index "users", ["email"], name: "index_users_on_email", unique: true

end

这里特别感兴趣的是:

# Could not dump table "simulations" because of following NoMethodError
#   undefined method `[]' for nil:NilClass

任何人都可以了解这里发生的事情或我如何解决这个问题?我已经坚持了几个小时。

有一件事值得注意,当我重新运行rake db:schema:dump时,由于某些原因,我需要注释掉我的工厂,因为它们似乎会导致模拟表存在错误。不确定为什么他们被调用只是认为这个信息可能会有所帮助,这里他们都是:

FactoryGirl.define do 
    factory :simulation do |f|
        f.id (Simulation.last.nil? ? 1 : Simulation.last.id + 1)
        f.x_size 3
        f.y_size 3
        f.user_id 1
    end 
end 

-

FactoryGirl.define do
    factory :user do
        email "user_#{User.last.nil? ? 1 : User.last.id + 1}@home.com"
        password "password"
    end
end

1 个答案:

答案 0 :(得分:1)

我认为问题就在这里:

class AddOpinionToSimulations < ActiveRecord::Migration
  def change
    add_column :simulations, :opinion, :hash
  end
end

没有hash列类型。遗憾的是,SQLite将允许您创建任何类型的列(将无法识别的内容视为字符串),但ActiveRecord不知道如何处理它们。结果是您的迁移工作正常,但架构转储失败,因为ActiveRecord不能说:

t.hash :opinion

schema.rb文件中。

如果您真的认为要在列中存储哈希值,则需要创建text列:

add_column :simulations, :opinion, :text

然后在模型中使用serialize

serialize :opinion, Hash

当然,在您的数据库中留下了一个不透明的YAML blob,您无法(明智地)查询,因此只有在您可以使用它时才能使用它。

更好的解决方案是规范化opinion哈希值,以便将信息存储在单独的表格/模型中。