Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby on Rails id column not generated after db:migration

I'm following a course on coursera and I'm on my first assignment details of which can be found on this and this link. WHen I ran rspec I found the test cases to be failing, turned out my schema didn't have an ID column in it. In the course it said that when I run migration the ID column is generated automatically just like created_at and updated_at. Anyone has any idea why the id column probably didn't get generated. I know I can overcome the problem by specifying it in a new migration but just wanted to know the reason.

Here's the Schema I currently have:

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

This is the migrations for 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

The model class it generated:

class TodoList < ActiveRecord::Base
end

My method that is inserting a record in it in the assignment.rb file as asked:

 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 code that is failing:

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  

Actual message that I get when it fails the test:

Failures:

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)>'
like image 630
Dashing Boy Avatar asked Nov 21 '25 09:11

Dashing Boy


1 Answers

The schema won't show the ID column. I double checked with one of my rails apps:

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

And when I describe the table in Postgres with \d users, I see the id column:

         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           |

If there is a reason you don't want the ID, you can omit it by passing id: false to create_table.

create_table :users, id: false do |t|
  #...
end

Probably a horrible idea on the users table :-)


Update

Looks like you are not actually creating a new TodoList.

The clue here is in the error: "undefined method 'id' for nil:NilClass". Your testList is nil.

One good tip is to always use the ActiveRecord's "bang" methods in tests. This will cause them to throw an exception if they fail. Which is super helpful when trying to track down errors -- you'll find the place with the actual error and not some side effect down the line.

I bet you can update your create_todolist to help track this down

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

I would also update your spec, by changing:

  testList = TodoList.find_by list_name: 'mylist'

To use the bang:

  testList = TodoList.find_by! list_name: 'mylist'
like image 157
csexton Avatar answered Nov 24 '25 01:11

csexton



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!