Ruby on Rails 数据库迁移后未生成ID列

3
我正在参加一门关于Rails with Active Record的Coursera课程,我正在完成我的第一个作业。作业的详细信息可以在这个链接这个链接中找到。当我运行rspec时,我发现测试用例失败了,原来我的模式中没有ID列。课程中说,当我运行迁移时,ID列会像created_at和updated_at一样自动生成。有人知道为什么可能没有生成id列吗?我知道我可以通过在新的迁移中指定它来解决问题,但只是想知道原因。
以下是我当前拥有的架构:
ActiveRecord::Schema.define(version: 20161108162529) do

  create_table "profiles", force: :cascade do |t|
    t.string   "gender"
    t.integer  "birth_year"
    t.string   "first_name"
    t.string   "last_name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "todo_items", force: :cascade do |t|
    t.date     "due_date"
    t.string   "title"
    t.text     "description"
    t.boolean  "completed",   default: false
    t.datetime "created_at",                  null: false
    t.datetime "updated_at",                  null: false
  end

  create_table "todo_lists", force: :cascade do |t|
    t.string   "list_name"
    t.date     "list_due_date"
    t.datetime "created_at",    null: false
    t.datetime "updated_at",    null: false
  end

  create_table "users", force: :cascade do |t|
    t.string   "username"
    t.string   "password_digest"
    t.datetime "created_at",      null: false
    t.datetime "updated_at",      null: false
  end

end

这是todolist的迁移内容:
class CreateTodoLists < ActiveRecord::Migration
  def change
    create_table :todo_lists do |t|
      t.string :list_name
      t.date :list_due_date

      t.timestamps null: false
    end
  end
end

它生成的模型类:
class TodoList < ActiveRecord::Base
end

按照要求在assignment.rb文件中插入记录的方法:

 def create_todolist(params)
      # accept a hash of todolist properties (`:name` and `:due_date`) as an input parameter. Note these are not 100% the same as Model class.
      # use the TodoList Model class to create a new user in the DB
      # return an instance of the class with primary key (`id`), and dates (`created_at` and `updated_at`) assigned
      t1 = TodoList.new
      t1.list_name = params["name"]
      t1.list_due_date = params["due_date"]
      t1.save
      TodoList.first
  end

无法通过的rspec代码:

context "rq03.2 assignment code has create_todolist method" do
        it { is_expected.to respond_to(:create_todolist) } 
        it "should create_todolist with provided parameters" do
            expect(TodoList.find_by list_name: "mylist").to be_nil
            due_date=Date.today
            assignment.create_todolist(:name=> 'mylist', :due_date=>due_date)
            testList = TodoList.find_by list_name: 'mylist'
            expect(testList.id).not_to be_nil
            expect(testList.list_name).to eq "mylist"
            expect(testList.list_due_date).to eq due_date
            expect(testList.created_at).not_to be_nil
            expect(testList.updated_at).not_to be_nil
        end  

当测试失败时,我收到的实际消息:

失败:

1) Assignment rq03 rq03.2 assignment code has create_todolist method should create_todolist with provided parameters
     Failure/Error: expect(testList.id).not_to be_nil

     NoMethodError:
       undefined method `id' for nil:NilClass
     # ./spec/assignment_spec.rb:173:in `block (4 levels) in <top (required)>'
     # ./spec/assignment_spec.rb:14:in `block (2 levels) in <top (required)>'

你能展示一下你的迁移吗?它们位于 /db/migrate 目录下。 - Richard Peck
你怎么能说ID列没有生成?FYI模式文件中没有显示ID列。 - APS
已更新原帖并附上所有相关细节。 - Dashing Boy
1个回答

2
模式不会显示ID列。我在我的一个Rails应用程序中进行了双重检查:
db/schema.rb
create_table "users", force: :cascade do |t|
  t.string   "email",                  default: "",    null: false
  t.string   "first_name"
  t.string   "last_name"
end

当我在Postgres中使用\d users命令来描述表格时,我可以看到id列:

         Column         |            Type             |                     Modifiers
------------------------+-----------------------------+----------------------------------------------------
 id                     | integer                     | not null default nextval('users_id_seq'::regclass)
 email                  | character varying           | not null default ''::character varying
 first_name             | character varying           |
 last_name              | character varying           |

如果您不想要ID,可以通过将 id: false 传递给create_table 来省略它。
create_table :users, id: false do |t|
  #...
end

users表上可能是个可怕的想法 :-)


更新

看起来你并没有创建一个新的TodoList

线索在于错误信息:"undefined method 'id' for nil:NilClass"。你的testList是空的。

一个好的提示是在测试中始终使用ActiveRecord的“bang”方法。这将导致它们在失败时抛出异常。当尝试跟踪错误时,这非常有帮助--你会找到实际错误的地方而不是一些副作用。

我敢打赌你可以更新你的create_todolist来帮助追踪这个问题。

def create_todolist(params)
  # Updated: To use ActiveRecord create! method. 
  # This will throw an exception if it fails.
  TodoList.create!(list_name: params[:name], due_date: params[:due_date])
end

我会更新您的规格,将其更改为:

我还会更新您的规格,将以下内容更改:

  testList = TodoList.find_by list_name: 'mylist'

使用Bang的方法如下:
  testList = TodoList.find_by! list_name: 'mylist'

嗨,我更新了这篇文章。现在你能告诉我有什么问题吗? - Dashing Boy
谢谢,这个方法可行,但是你能告诉我我哪里做错了吗?我认为我的操作完全正确。 - Dashing Boy
我认为你没有做错任何事。使用返回nil而不是引发异常的Active Model方法只是掩盖了问题。由于你在错误的地方寻找,所以很令人困惑。幸运的是,你正在编写测试,因此追踪问题变得容易多了 - csexton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接