The documentation shows a clear example on how to do it for one resource:
post = Post.find(1)
JSONAPI::ResourceSerializer.new(PostResource).serialize_to_hash(PostResource.new(post, nil))
But how does one serialize an array of resources?
For example, suppose this is my controller:
class ProductsController < ApplicationController
def index
@products = Product.where(visible: true)
render json: JSONAPI::ResourceSerializer.new(ProductResource).serialize_to_hash(ProductResource.new(@products, nil))
end
def show
product = Product.find(params[:id])
render json: JSONAPI::ResourceSerializer.new(Admin::ProductResource).serialize_to_hash(ProductResource.new(product, nil))
end
end
GET /products/2
The show method returns 1 resource in JSON API compliant format. Even better, I could remove the entire show method and it will still work because the inherited methods do something similar.
GET /products/
However, the index method returns a 500 error. Removing the index method entirely would partially solve the problem, I get an array back containing ALL products. But what if I need it to return only the active=true products? For that I need an array serializer no?
Suggestions?
Am I missing something?
Is the documentation incomplete?
Have I perhaps not understood how to work with JSON API? I've got the impression the idea is to not add any logic to your controllers at all and let the URLs do all the work?
It took me a little while to find this because it seems like the source code has changed dramatically from 0.9 to what's in master? I had to dig into the source for the installed gem, as the docs didn't cover it and master is somewhat different.
Instead of passing the array of @products to ProductResource.new, you need to pass an array of ProductResources to serialize_to_hash. So, the correct way appears to be:
def index
@products = Product.where(visible: true)
@product_resources = @products.map { |product| ProductResource.new(product, nil) }
render json: JSONAPI::ResourceSerializer.new(ProductResource).serialize_to_hash(@product_resources)
end
Brilliant, that works!
Why is there so much complexity for rendering a resource? I'm trying to find a good gem for using JSON API in my rails project, and I'm not a huge fan of the magical controllers
class ProductController < JSONAPI::ResourceControllerMetal
# magic!
end
Without looking in the source code, I can't seem to find any documentation on what's happening in the controllers or how to explicitly render using a resource. It seems overly complex to have to call the following to render multiple resources.
@products = Product.where(visible: true)
@product_resources = @products.map { |product| ProductResource.new(product, nil) }
render json: JSONAPI::ResourceSerializer.new(ProductResource).serialize_to_hash(@product_resources)
@KidA001
I agree, the JSON API Resources controllers contain too much unknown and undocumented "magic". I'm uncertain how to use them, so I've resorted to overwriting them entirely and leverage Resources as serialisers only. For example:
# app/controllers/admin/products_controller.rb
def index
@products = Product.all
render status: 200, json: json_resources(Admin::ProductResource, @products)
end
def show
@product = Product.find(params[:id])
render status: 200, json: json_resource(Admin::ProductResource, @product)
end
def create
@product = Product.new(attributes)
@product.product_group_id = relationships[:'product-group']['data']['id']
@product.product_sub_group_id = relationships[:'product-sub-group']['data']['id']
if @product.save!
render status: 201, json: json_resource(Admin::ProductResource, @product)
else
render status: 422, json: json_errors(@product)
end
end
```ruby
class ApplicationController < JSONAPI::ResourceController
# Serialise and return 1 record into JSON using JSON API resources
# Example: render status: 200, json: json_resource(Admin::ProductResource, @product, nil)
def json_resource(klass, record, context = nil)
JSONAPI::ResourceSerializer.new(klass).serialize_to_hash(klass.new(record, context))
end
# Serialise and return an array of records into JSON using JSON API resources
# Example: render status: 200, json: json_resources(Admin::ProductResource, @products, nil)
def json_resources(klass, records, context = nil)
resources = records.map { |record| klass.new(record, context) }
JSONAPI::ResourceSerializer.new(klass).serialize_to_hash(resources)
end
end
```ruby
# app/resources/admin/product_resource.rb
module Admin
class ProductResource < JSONAPI::Resource
attributes :name,
:slug,
:public,
:pitch,
:body
relationship :product_group, to: :one
relationship :product_sub_group, to: :one
end
end
@btoconnor
Your method does work . but when you check the content-type it is application/json
instead of application/vnd.api+json
I'm using jsonapi-resources 0.10.2
It appears the method JSONAPI::ResourceSerializer#serialize_to_hash does not exist, but there are some variants such as JSONAPI::ResourceSerializer#serialize_resource_set_to_hash_single That method, however, requires a ResourceSet as a parameter. not an ActiveRecord. It was not clear to me how to come by the required ResourceSet object.
TY!
Most helpful comment
Why is there so much complexity for rendering a resource? I'm trying to find a good gem for using JSON API in my rails project, and I'm not a huge fan of the magical controllers
Without looking in the source code, I can't seem to find any documentation on what's happening in the controllers or how to explicitly render using a resource. It seems overly complex to have to call the following to render multiple resources.