What should the strong parameters for my chapters_controller
be if I have a Book
entity and a Chapter
entity?
Note: I am using JSON API.
In my chapters_controller
, should my strong parameters be:
:title, :order, :content, :published, :book, :picture
Or should it be:
:title, :order, :content, :published, :book_id, :picture
If I use :book
instead of :book_id
, then in my Ember application, when I go to create a new chapter, I am able to create it and associate this chapter to the parent book, however, my test fails:
def setup
@book = books(:one)
@new_chapter = {
title: "Cooked Wolf Dinner",
order: 4,
published: false,
content: "The bad wolf was very mad. He was determined to eat the little pig so he climbed down the chimney.",
book: @book
}
end
def format_jsonapi(params)
params = {
data: {
type: "books",
attributes: params
}
}
return params
end
...
test "chapter create - should create new chapter assigned to an existing book" do
assert_difference "Chapter.count", +1 do
post chapters_path, params: format_jsonapi(@new_chapter), headers: user_authenticated_header(@jim)
assert_response :created
json = JSON.parse(response.body)
attributes = json['data']['attributes']
assert_equal "Cooked Wolf Dinner", attributes['title']
assert_equal 4, attributes['order']
assert_equal false, attributes['published']
assert_equal @book.title, attributes['book']['title']
end
end
I get error in my console saying Association type mismatch.
Perhaps my line:
book: @book
is causing it?
Either way, gut feeling is telling me I should be using :book
in my chapters_controller
strong parameters.
It's just my test isn't passing, and I am not sure how to write the parameter hash for my test to pass.
After a few more hours of struggle and looking at the JSON API docs:
http://jsonapi.org/format/#crud-creating
It has come to my attention, in order to set a belongsTo relationship to an entity with JSON API, we need do this:
POST /photos HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json
{
"data": {
"type": "photos",
"attributes": {
"title": "Ember Hamster",
"src": "http://example.com/images/productivity.png"
},
"relationships": {
"photographer": {
"data": { "type": "people", "id": "9" }
}
}
}
}
This also led me to fixing another problem I had in the past which I couldn't fix. Books can be created with multiple genres.
The JSON API structure for assigning an array of Genre
to a Book
entity, we replace the data hash with a data array in the relationship part like this:
"data": [
{ "type": "comments", "id": "5" },
{ "type": "comments", "id": "12" }
]
Additonally, in my controllers, anything strong parameters like so:
:title, :content, genre_ids: []
Becomes
:title, :content, :genres
To comply with JSON API.
So for my new test sample datas I now have:
def setup
...
@new_chapter = {
title: "Cooked Wolf Dinner",
order: 4,
published: false,
content: "The bad wolf was very mad. He was determined to eat the little pig so he climbed down the chimney.",
}
...
end
def format_jsonapi(params, book_id = nil)
params = {
data: {
type: "chapters",
attributes: params
}
}
if book_id != nil
params[:data][:relationships] = {
book: {
data: {
type: "books",
id: book_id
}
}
}
end
return params
end
Special note on the relationship settings - only add relationships
to params
if there is a relationship, otherwise, setting it to nil is telling JSON API to remove that relationship, instead of ignoring it.
Then I can call my test like so:
test "chapter create - should create new chapter assigned to an existing book" do
assert_difference "Chapter.count", +1 do
post chapters_path, params: format_jsonapi(@new_chapter, @book.id), headers: user_authenticated_header(@jim)
assert_response :created
json = JSON.parse(response.body)
attributes = json['data']['attributes']
assert_equal "Cooked Wolf Dinner", attributes['title']
assert_equal 4, attributes['order']
assert_equal false, attributes['published']
assert_equal @book.id, json['data']['relationships']['book']['data']['id'].to_i
end