ActiveModel::Serializer not allowing me to load serializer in app/serializers - ruby-on-rails

I have the following api controller in ('app/controllers/api/v1/companies_controller.rb'):
class Api::V1::CompaniesController < ApplicationController
def index
companies = Company.all
render json: companies, serializer: CompanySerializer
end
end
but the above is looking for Api::V1::CompanySerializer in app/serializers/api/v1/company_serializer.rb. I'd rather just have a generic company serializer in app/serializers/company_serializer. I have tried using the scope resolution operator like:
render json: companies, serializer: ::CompanySerializer
but still getting an error. How would I tell my controller to use the default serializer explicitly? I have seen this issue https://github.com/rails-api/active_model_serializers/issues/1701 and, if this is the ONLY behavior allowed, it seems like a strange choice

AMS 0.10.7 Implicit Serializer vs Explicit Serializer
You really don't need to pass any serializer option as long as your serializer has the default name. So render json: companies should work.
Explicit way would look like:
render json: companies,
serializer: CollectionSerializer,
each_serializer: CompanySerializer
Note: The default serializer for collections is CollectionSerializer. In your example, you tried to pass CompanySerializer to serializer.

Related

In Rails, How do you apply different serializers for each model/object in the same render?

In my render, I have
reder json: {code_names: #code_names, rows: #tables}, each_serializer: FreeTableSerializer
Where #code_names is just an arbitrary list, which doesn't matter much in our problem, and #tables can be a collection of obejcts of one model.
If I use each_serializer in this case, I'm assuming the each goes trough json's "children", which are both lists and it ends up not applying the serializer into #tables.
I want a way to return both #code_names and #tables with #tables using a Serializer that is no its default.
I tought about making a single variable that is a single list, but I need a way to identify both code and tables.
you can define a composite serializer
class ACompositeSerializer < ActiveModel::Serializer
def serializable_hash
tables_serializer_hash.merge code_names_serializer_hash
end
private
def tables_serializer_hash
FreeTableSerializer.new(object, options).serializable_hash
end
def code_names_serializer_hash
CodeNameSerializer.new(object, options).serializable_hash
end
end
update
in your case, i think just simple like this:
render json: {
code_names: #code_names.as_json,
rows: ActiveModel::Serializer::CollectionSerializer.new(
#tables,
serializer: FreeTableSerializer
)
}

Active Model Serializer not responding with the correct attributes

I am working on a rails-api project where I am using active model serialiazer. But unfortunately its not working as expected. This is my V1::HuntsController
class V1::HuntsController < V1::MainController
def index
render json: Hunt.all
end
end
My hunts serializer looks like this
class HuntSerializer < ActiveModel::Serializer
belongs_to :user
attributes :id,:title,:picture_url,:clue
private
def picture_url
object.picture.url
end
end
But in my response i am getting all the attributes from hunt. I tried to explicitly define serializer to avoid versioning issues as well.
render json: {data: Hunt.all } ,each_serializer: HuntSerializer
But nothing seems to work. In the logs I can see,
[active_model_serializers] Rendered V1::HuntSerializer with Hash (32.36ms)
Whats happening here. Any help would be appreciated.
try
render json: Hunt.all, each_serializer: HuntSerializer (no need for data root)
then to verify that the serializer gets hit, put a byebug in the body of the picture_url function. if the byebug gets hit, you are indeed using your serializer. (must have gem byebug included in gemfile)

rails 5 api app jsonapi CollectionSerializer type override on serialization

Using the jsonapi serialization as the default serialization type, does anyone know how to get the collection type included when serializing the collection?
I've tried specifying a custom serializer for the resource and overriding the type, but I get an error
NoMethodError (undefined method `type' for UsersSerializer:Class):
class UsersSerializer < ActiveModel::Serializer::CollectionSerializer
type 'users'
end
or
class UsersSerializer < ActiveModel::Serializer::CollectionSerializer
def json_key
"users"
end
end
the last one doesn't throw an error but also doesn't emit the type
the output I'd like to have is one consistent with the jsonapi with a type property on the returned object. i.e.
{
"type": "users",
"data": [{user}{user}{user}]
}
what I am currently getting is
{
"data: [{user},{user},{user}]
}
when I call the following from my controller
render json: #users, serializer: UsersSerializer, each_serializer: UserSerializer
or
render json: #users, serializer: UsersSerializer, :root='users', each_serializer: UserSerializer
or
render json: #users, serializer: UsersSerializer, json_key='users' each_serializer: UserSerializer
I know what I am trying to do is probably simple, but searching for 'ruby rails 5 api app jsonapi CollectionSerializer type' turns up a slew of information unrelated to what I am trying to accomplish.
Any help is greatly appreciated.
After additional research, the 'type' attribute is not part of the json-api spec at the root. Instead, I have opted to use the 'meta' attribute on the top level collection type. i.e.
render json: #users, serializer: UsersSerializer, :meta=>{:type=>"users"}, each_serializer: UserSerializer

ActiveModelSerializers gem: how to pass parameter to serializer

I'm updating the gem active_model_serializers from version 0.9.5 to 0.10.1. For version 0.9.5 the code below worked.
Controller:
def create
...
render json: #dia, app_rights: app_rights(#dia)
end
Serializer:
class Api::V1::SerializerWithSessionMetadata < ActiveModel::Serializer
attributes :app_rights
def app_rights
serialization_options[:app_rights]
end
end
The method serialization_options has been deprecated in version 0.10.1.
Here it is suggested to use instance_options instead.
Here it is suggested to use options: "instance_options is only available in the master branch, not in the current RC. In the current RC, you have to use options instead".
There are also suggestions for #options and #instance_options.
I have tried replacing serialization_options with all the above options. However, in all cases, after updating the gem, the json produced does not include app_rights. What am I doing wrong?
Using instance_options, your serializer should look like this:
class Api::V1::SerializerWithSessionMetadata < ActiveModel::Serializer
attributes :app_rights
def app_rights
#instance_options[:app_rights]
end
end
To ensure that the correct serializer gets called, you can render a specific serializer like this (otherwise it will render whatever is defined for the class on #dia):
render json: #dia, serializer: SerializerWithSessionMetadata, app_rights: app_rights(#dia)

Rails ActiveModel::Serializer nest response in "data": parent

I have a rails app in which I use the gem active_model_serializers. In my responses I would like to nest my results inside a "data": parent. Currently when I don't get any data for a response I get the following JSON:
[]
What I want is something like this:
{
"data": []
}
I would also like to use the same format in cases where I have data, like this:
{
"data": [
{
"id": 135,
[...]
I've managed to get the structure I want by using render json, like this:
render json: { data: respond_values}
But in this case my serialiser gets ignored and all the attributes in my model gets returned. My serialiser looks like this:
class TranslationSerializer < ActiveModel::Serializer
attributes :id, :value, :created_at, :updated_at, :language_id
has_one :language
has_one :localized_string, serializer: LocalizedStringParentSerializer
end
If I instead use respond_with my serialiser works but I don't get the structure I want - the data parent / container is missing.
Any ideas on what I need to to to get my serialiser to work properly?
First off unless you need to support a legacy API use the JSON:API adapter:
By default ActiveModelSerializers will use the Attributes Adapter (no
JSON root). But we strongly advise you to use JsonApi Adapter, which
follows 1.0 of the format specified in jsonapi.org/format.
While nobody fully agrees with all the design decisions in JSON:API it is widely supported by front-end frameworks such as Ember and Angular and is likely to gain further traction.
Otherwise you would need to create your own adapter since the JSON adapter does not allow you to set the root key.
# lib/active_model_serializers/adapters/bikeshed_adapter.rb
module ActiveModelSerializers
module Adapters
class BikeshedAdapter < Json
def root
:data
end
end
end
end
ActiveModelSerializers.config.adapter = :bikeshed
For any reason, Rails is not finding a Serializer which matches to the model. Maybe something is missing in the convention name/namespace of your model with serializer.
https://github.com/rails-api/active_model_serializers/blob/master/docs/general/rendering.md
But, if you explicit declare the serializer, it should work.
render json: #post, serializer: PostPreviewSerializer

Resources