Search code examples
ruby-on-railsjson-api

Rails JSON_API create Book with list of Genres


I'm trying to write my test to ensure creating a new book with genres assigned to it works.

I am using Active Model Serializer with the JSON_API structure (http://jsonapi.org/)

Book Model File

class Book < ApplicationRecord
  belongs_to :author, class_name: "User"
  has_and_belongs_to_many :genres
end

Genre Model File

class Genre < ApplicationRecord
  has_and_belongs_to_many :books
end

Book Serializer file

class BookSerializer < ActiveModel::Serializer
  attributes :id, :title, :adult_content, :published

  belongs_to :author
  has_many :genres
end

Test Sample Data

def setup
    ...
    @fantasy = genres(:fantasy)

    @newbook = {
      title: "Three Little Pigs",
      adult_content: false,
      author_id: @jim.id,
      published: false,
      genres: [{title: 'Fantasy'}]
    }
end

Test Method

test "book create - should create a new book" do
    post books_path, params: @newbook, headers: user_authenticated_header(@jim)
    assert_response :created
    json = JSON.parse(response.body)
    puts "json = #{json}"
    assert_equal "Three Little Pigs", json['data']['attributes']['title']
    genre_data = json['data']['relationships']['genres']['data']

    puts "genre_data = #{genre_data.count}"
    assert_equal "Fantasy", genre_data
end

Book Strong Params

def book_params
    params.permit(:title, :adult_content, :published, :author_id, :genres)
end

Test Result (console response)

# Running:

......................................................json = {"data"=>{"id"=>"1018350796", "type"=>"books", "attributes"=>{"title"=>"Three Little Pigs", "adult-content"=>false, "published"=>false}, "relationships"=>{"author"=>{"data"=>{"id"=>"1027431151", "type"=>"users"}}, "genres"=>{"data"=>[]}}}}
genre_data = 0
F

Failure:
BooksControllerTest#test_book_create_-_should_create_a_new_book [/Users/warlock/App_Projects/Raven Quill/Source Code/Rails/raven-quill-api/test/controllers/books_controller_test.rb:60]:
Expected: "Fantasy"
  Actual: []


bin/rails test test/controllers/books_controller_test.rb:51



Finished in 1.071044s, 51.3518 runs/s, 65.3568 assertions/s.

55 runs, 70 assertions, 1 failures, 0 errors, 0 skips

As you can see from my JSON console log, it appears my genres are not being set(need to scroll to the right in the test output above).

Please ignore this line:

assert_equal "Fantasy", genre_data

I know that's wrong. At the moment, the json is showing genre => {data: []} (empty array), that's the thing I'm trying to solve at the moment.

How do I go about creating a book with genres in this case, any ideas? :D


Solution

  • This is just sad...third time this week, I am answering my own question.

    I finally found the answer from this Stackoverflow question:

    HABTM association with Strong Parameters is not saving user in Rails 4

    Turns out my strong parameters need to be:

    def book_params
        params.permit(:title, :adult_content, :published, :author_id, {:genre_ids => []})
    end
    

    Then my test data can be:

    @fantasy = genres(:fantasy)
    
    @newbook = {
      title: "Three Little Pigs",
      adult_content: false,
      author_id: @jim.id,
      published: false,
      genre_ids: [@fantasy.id]
    }
    

    Update my test method to:

    test "book create - should create a new book" do
        post books_path, params: @newbook, headers: user_authenticated_header(@jim)
        assert_response :created
        json = JSON.parse(response.body)
        assert_equal "Three Little Pigs", json['data']['attributes']['title']
        genre = json['data']['relationships']['genres']['data'].first['title']
        assert_equal "Fantasy", genre
    end
    

    Now my test passes.