Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Ruby

`save' for nil:NilClass

I need some help with with error I keep getting.

Failure/Error: click_link "List Items"
     ActionController::RoutingError:
       undefined method `save' for nil:NilClass
     # ./app/controllers/todo_items_controller.rb:16:in `<class:TodoItemsController>'
     # ./app/controllers/todo_items_controller.rb:1:in `<top (required)>'
     # ./spec/features/todo_items/create_spec.rb:9:in `block in visit_todo_list'
     # ./spec/features/todo_items/create_spec.rb:8:in `visit_todo_list'
     # ./spec/features/todo_items/create_spec.rb:14:in `block (2 levels) in <top (required)>'

create_spec

require 'spec_helper'

describe "Adding 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("Adding tdo list item.")
    within("ul.todo_items") do
      expect(page). to have_content("Milk")
    end
  end
end

todo_items_controller

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

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

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

    if @todo_item.save
        flash[:success] = "Added todo list item"
        redirect_to todo_list_todo_items_path
    else
        flash[:error] = "There was a problem adding that todo list item"
        render action: :new

  end


    private

        def todo_item_params
            params [:todo_item].permit(:content)
        end
end

Any help would be Fantastic been working on this for a while now and coming up with nothing.

3 Answers

You ended the create method before the save could do anything. Move that end after the whole if/else expression.

so like this?

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

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

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

    if @todo_item.save
        flash[:success] = "Added todo list item"
        redirect_to todo_list_todo_items_path
    else
        flash[:error] = "There was a problem adding that todo list item"
        render action: :new
    end



    private

        def todo_item_params
            params [:todo_item].permit(:content)
        end
    end
end

if it's like that then I get this error.... feel like its staring me in the face but just not seeing it....

     Failure/Error: click_button "Save"
     NameError:
       undefined local variable or method `todo_item_params' for #<TodoItemsController:0x007fc6e7b45a18>
     # ./app/controllers/todo_items_controller.rb:13:in `create'
     # ./spec/features/todo_items/create_spec.rb:17:in `block (2 levels) in <top (required)>'

but thank you for your help =D

Almost there:

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

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

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

    if @todo_item.save
        flash[:success] = "Added todo list item"
        redirect_to todo_list_todo_items_path
    else
        flash[:error] = "There was a problem adding that todo list item"
        render action: :new
    end
  end

private

   def todo_item_params
       params [:todo_item].permit(:content)
   end

end

Thank you feel a bit silly for missing that one ^^" did the change but now I'm getting

     Failure/Error: click_button "Save"
     NoMethodError:
       undefined method `permit' for [:todo_item]:Array
     # ./app/controllers/todo_items_controller.rb:27:in `todo_item_params'
     # ./app/controllers/todo_items_controller.rb:13:in `create'
     # ./spec/features/todo_items/create_spec.rb:17:in `block (2 levels) in <top (required)>'

sorry for bugging you with repeated error's

Yeah, didn't notice your private method, it should actually be:

   def todo_item_params
       params.require(:todo_item).permit(:content)
   end

Please watch the videos until you get it right. It's all in the details.

thank you and I will do =D though in the video he doesn't put .require I'm guessing thats to do with updates?

If that is the case would the Ruby documentation be the best place to start and try to work out what the issues is? as putting the .require as you mentioned it comes up with the same error message.

I've just been looking on the ruby documentation and the only item coming up with params is a gam called strong parameters (which I don't have in my Gemfile, which could be the issue) or am I looking in the wrong place?

Okay, just looked on the app though the sever and its working fine Save button and all.

Not sure what happen for it to give me an error one moment then working the next.

Strong Parameters are built-in to Rails 4 and above. If someone wanted to use them in previous versions or Rails, they had to use a gem. This should explain more how it works: http://www.lynda.com/Ruby-Rails-tutorials/Mass-assignment-strong-parameters/139989/159116-4.html

.require is not necessary, but it makes the whole thing safer, so it's a good practice.