Jacksonvoice
Jacksonvoice

Reputation: 93

Rails Rspec test fail: NoMethodError:

I'm learning rails and I'm not sure why I'm getting this test failure/error. Any explanation would be great! I'd like a solution but what I really need is to understand why I'm getting this failure in the first place so I know how to deal with this in the future.

Rails version is 4.1.1, Ruby version 2.0.0p353, Rspec version 3.0.1, Capybara 2.3.0

Here is the error

Failure/Error: click_link "New Todo Item"
 NoMethodError:
   undefined method `todo_item' for nil:NilClass
 # ./app/controllers/todo_items_controller.rb:8:in `new'
 # ./spec/features/todo_items/create_spec.rb:16:in `block (2 levels) in <top (required)>'

Here is the controller it is referring to app/controllers/todo_items_controller.rb

class TodoItemsController < ApplicationController
 def index
    @todo_list = TodoList.find(params[:todo_list_id])
 end

 def new
    @todo_item = TodoList.find(params[:todo_list_id])
    @todo_item = @todo_list.todo_items.new  
 end 
end

Here is the test spec/features/todo_items/create_spec.rb

require 'rails_helper'

describe "Viewing todo items" do 
let!(:todo_list) { TodoList.create(title: "Grocery List", description: "Groceries")}


def visit_todo_list(list)
    visit "/todo_lists"
    within "#todo_list_#{list.id}" do
        click_link "List Items"
    end
end

it "is successful with valid content" do
    visit_todo_list(todo_list)
    click_link "New Todo Item"
    fill_in "Content", with: "Milk"
    click_button "Save"
    expect(page).to have_content("Added Todo List Item.")
    within("ul.todo_items") do
        expect(page).to have_content("Milk")
    end
end
end

and this is the view that goes with it. app/views/todo_items/index.html.erb

<h1><%= @todo_list.title %></h1>
<p>testing 123</p>

<ul class="todo_items">
<% @todo_list.todo_items.each do |todo_item| %>
<li><%= todo_item.content %></li>
<% end %>
</ul>

<p>
<%= link_to "New Todo Item", new_todo_list_todo_item_path %>
</p>

Please let me know if you need anything else and thank you in advance!

Best,

Jackson

Upvotes: 0

Views: 454

Answers (1)

trosborn
trosborn

Reputation: 1668

@todo_item is nil because you are not defining @todo_list in the new method. Your want your new method to look like this:

def new
  @todo_list = TodoList.find(params[:todo_list_id])
  @todo_item = @todo_list.todo_items.new  
end 

However, this is not very DRY as you already are defining @todo_list inside your index method. You should make a new method called set_list, then use a before_action to call it prior to the relevant methods.

before action :set_list

def new
  @todo_item = @todo_list.todo_items.new 
end

private
  def set_list
    @todo_list = TodoList.find(params[:todo_list_id])
  end

Upvotes: 3

Related Questions