【问题标题】:Ruby on Rails id column not generated after db:migrationdb:migration 后未生成 Ruby on Rails id 列
【发布时间】:2016-11-11 22:06:10
【问题描述】:

我正在学习coursera 上的课程,我正在完成我的第一个作业,详细信息可以在thisthis 链接上找到。当我运行 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

这是 todolists 的迁移:

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
  • 你怎么能说id列没有生成呢?仅供参考的架构文件不显示 ID 列。
  • 用所有相关细节更新了原始帖子

标签: ruby-on-rails ruby


【解决方案1】:

架构不会显示 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

当我用 \d users 描述 Postgres 中的表时,我看到了 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

这里的线索在错误中:“nil:NilClass 的未定义方法 'id'”。您的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'

使用刘海:

  testList = TodoList.find_by! list_name: 'mylist'

【讨论】:

  • 嘿,我更新了帖子。你现在能告诉我怎么了吗?
  • 谢谢,这有效,但你能告诉我我做错了什么吗?我认为我所做的是完全正确的。
  • 我不认为你做错了什么。使用返回 nil 而不是引发异常的 Active Model 方法只是掩盖了问题。而且由于您在错误的地方寻找,这令人困惑。幸运的是,您正在编写测试,所以跟踪它要容易得多
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-27
  • 2013-04-18
  • 2011-08-02
  • 2013-05-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多