0

Im using Rails 4.1.6 and Ruby 2.1.3

bookmarks_controller.rb

class BookmarksController < ApplicationController
    def index
        @bookmarks = ListBookmarks.list
        render json: @bookmarks.to_json     
    end

    def create
        @bookmark = CreateBookmark.new(params[:bookmark]).create

        if @bookmark
            head 201
        else
            head 422
        end
    end
end

bookmarks_controller_test.rb

require 'test_helper'

class BookmarksControllerTest < ActionController::TestCase
  test "return ok status if bookmark is created" do
    post :create, bookmark: { title: "Tuts+", url: "http://tutsplus.com" }

    assert_response 201
  end

  test "returns not ok status if bookmark is not created" do
    post :create, bookmark: {}

    assert_response 422
  end
end

create_bookmark.rb

class CreateBookmark
    def initialize data
        @data = data
    end

    def create
        bookmark = Bookmark.new @data
        bookmark.save
    end
end

But when I run my test it returns:

ActiveModel::ForbiddenAttributesError:

I have change my bookmarks_controller.rb to this:

class BookmarksController < ApplicationController
    def index
        @bookmarks = ListBookmarks.list
        render json: @bookmarks.to_json     
    end

    def create
        @bookmark = CreateBookmark.new(bookmark_params).create

        if @bookmark
            head 201
        else
            head 422
        end
    end

    private 

    def bookmark_params
        params.require(:bookmark).permit(:title, :url)
    end
end

it returns following error:

ActionController::ParameterMissing: param is missing or the value is empty: bookmark
junior
  • 808
  • 15
  • 25
  • Why do you need classes like CreateBookmark or ListBookmark - it does seem to violate OOP principles. – BroiSatse Oct 25 '14 at 11:03
  • I just follow some tutorial sir, Im new to rails, but I guess its for testing purpose :( I don't want to break my learning path by trying another method, I just want to know how this is going to be, sorry. But do you have any solution sir? – junior Oct 25 '14 at 11:17
  • You are keeping secrets from us! I just tested your case and it works fine. Except that second test case fails but it's just an incorrect test.In general "ActionController::ParameterMissing:" error states that your request params was wrong and it's raised in your `params.require(:bookmark)` statement so I'm almost sure its typo in your tests or something. – Pavel S Oct 25 '14 at 11:29

2 Answers2

1

I see you updated your initial post. And as I guess your second test case fails now with ActionController::ParameterMissing.

First of all we need to clarify what happens in your code.

You are sending request: post :create, bookmark: {}, so params[:bookmark] is empty for sure. params.require(:bookmark) statement throws ActionController::ParameterMissing if params[:bookmark] is empty or missing.

Now lets think what you can do depending on your needs.

If you want bookmark_params to silently return empty hash in case of missing params[:bookmark] you can do this: params.fetch(:bookmark, {}).permit(:title, :url)

In real world applications its common pattern to use params.require and rescue ActionController::ParameterMissing using rescue_from helper in your ApplicationController. Maybe it's not in your tutorial yet.

If you want to test that your action does not create bookmark with invalid input you can try to send request with invalid data e.g. post :create, bookmark: {asdasdasd: nil}.

Pavel S
  • 389
  • 1
  • 9
  • Ah it works now, yes I thinK it's not yet in my tutorial, the tutorial I follow used Rails 4.0.4, But how do I get this information sir? – junior Oct 25 '14 at 12:42
  • @junior you can read about strong params [here](http://api.rubyonrails.org/classes/ActionController/StrongParameters.html) and [here](http://api.rubyonrails.org/classes/ActionController/Parameters.html). – Pavel S Oct 25 '14 at 12:50
0

I changed the bookmark_params method to this, and it works:

def bookmark_params
   params[:bookmark].permit!
end
junior
  • 808
  • 15
  • 25
  • This is not the best solution since if you send `create` request without bookmark param at all it will raise `NoMethodError: undefined method 'permit!' for nil` which is very general error and is not convenient to handle in controllers. So I'd recommend you to keep `params.require(:bookmark)` and solve the original problem. The `ActionController::ParameterMissing` exception can be treated as invalid request with high degree of confidence so you can respond with 422. – Pavel S Oct 25 '14 at 11:38
  • @PavelS OK I have changed my code again to params.require[:bookmark].permit(:title, :url) and it throws ArgumentError: wrong number of arguments (0 for 1), the error is point to bookmarks_controller.rb and bookmarks_controller_test.rb – junior Oct 25 '14 at 12:13