Here's the response my Rails app is giving me:
{"users":[{"users":{"id":20,"email":"subscriber#email.com", ...
Here's what it should looks like (this is for another working resource):
{"companies":[{"id":448,"name":"Microsoft Security ...
Notice the wrapping users: object.
Here's my Serializer for the User model:
class UserSerializer < ApplicationSerializer
attributes :id,
:first_name,
:last_name
end
And for the Company model:
class CompanySerializer < ApplicationSerializer
attributes :id, :name
end
What am I missing? What I need to do so the json response uses this UserSerializer class?
def index
load_users
render json: #users
end
I knew it was a problem with Rails somehow ignoring my Serializer.
In my controller I wrote this:
# app/controllers/api/v1/users_controller.rb:
class Api::V1::UsersController < ApplicationController
def default_serializer_options
{ each_serializer: UserSerializer } # I use each_serializer instead of serializer because it's rendering a collection.
end
end
Basically I man-handled the code to use the right serializer and it's working fine now.
Related
having a problem with sending parameters.
I have user_serializer and book_serializer and I want to send user_id to book_serializer inside user_serializer. Like this:
class UserSerializer < ActiveModel::Serializer
attributes :id
has_many :books, serializer: BookSerializer, your_option_name: object.id
end
and then BookSerializer
class BookSerializer < ActiveModel::Serializer
attributes :id, :test
def test
#instance_options[:your_option_name]
end
end
but it's not working, getting null.
are there any ideas? great thanks.
The arguments that you passed into has_many ... is actually used to create a HasManyReflection object which only accepts some very specific values and it also does not pass its argument any further.
The correct way to pass custom argument to nested serializers is through the build_association method or directly like below:
class UserSerializer < ActiveModel::Serializer
attributes :id, books
def books
ActiveModel::SerializableResource.new(object.books, each_serializer: BookSerializer, your_option_name: object.id)
end
end
I have the folowing ASM 0.10 :
class UserMicroSerializer < ActiveModel::Serializer
attributes :id, :name, :is_friend
def is_friend
#instance_options[:is_friend]
end
end
but would also like to support not having the is_friend attribute.
I have tried various things like:
class UserMicroSerializer < ActiveModel::Serializer
attributes :id, :name
if #instance_options[:is_friend]
attributes :is_friend
end
def is_friend
#instance_options[:is_friend]
end
end
but get error msg:
NoMethodError: undefined method `[]' for nil:NilClass
How would I make the #instane_options conditionally include is_friend?
If you can conditionally use a different serializer in the controller then you may be able to do this
class SimpleUserMicroSerializer < ActiveModel::Serializer
attributes :id, :name
end
By subclassing the simple serializer, you don't have much code overlap
class UserMicroSerializer < SimpleUserMicroSerializer
attributes :is_friend
def is_friend
#instance_options[:is_friend]
end
end
You can also send { scope: 'is_friend' } from controller and then check it into serializer.
class UserMicroSerializer < ActiveModel::Serializer
attributes :id, :name, :is_friend
def filter(keys)
keys.delete :is_friend if scope and scope[:is_friend]
super(keys)
end
end
I have a model called Event. An Event has_and_belongs_to_many :event_sub_categories and a EventSubCategory has_and_belongs_to_many :events. I have the following action:
def index
#events = Event.where(begins_at: DateTime.now.beginning_of_day..1.week.from_now).group_by{|e| e.begins_at.beginning_of_day}.to_a.to_json
render json: #events
end
The action returns the data exactly as needed except for one problem, it doesn't have subcategories. I need the json to contain the subcategories. I tried making the following ActiveModel Serializer:
class EventSerializer < ActiveModel::Serializer
attributes :id, :name, :event_sub_categories
end
but the serializer above doesn't change the json at all. How do I fix this?
try
class EventSerializer < ActiveModel::Serializer
attributes :id, :name
has_many :event_sub_categories
end
Try this:
1- In your controller modify the query in a way it includes the event_sub_categories:
def index
#events = Event.includes(:event_sub_categories).where(begins_at: DateTime.now.beginning_of_day..1.week.from_now).group_by{|e| e.begins_at.beginning_of_day}.to_a.to_json
render json: #events
end
2- create a Serializer for EventSubCategory model
3- in your Event serializer create the method event_sub_categories
class EventSerializer < ActiveModel::Serializer
attributes :id, :name, :event_sub_categories
def event_sub_categories
object.event_sub_categories.map do |sub_category|
EventSubCategorySerializer.new(sub_category)
end
end
end
I'm learning how to use active_model_serializers (gem). In an organization serializer I have:
has_many :nodes
So now when I make an API request for the data for an organization, it automatically also sends the attributes for the associated nodes.
For example, a GET request to the show method of the organizations controller, generates JSON that includes attributes for organization as well as the nodes. This works.
This is perfect for the show method, but for a GET request to the index method I would like it to only include the attributes for the organization and not for the associated nodes. Is this possible?
You can create different serializers for different actions:
class ShallowOrganizationSerializer < ActiveModel::Serializer
attributes :id, :name # ....
end
class DetailedOrganizationSerializer < ShallowOrganizationSerializer
has_many :nodes
end
And in your controller:
class OrganizationController < ApplicationController
def index
# ...
render json: #organizations, each_serializer: ShallowOrganizationSerializer
end
def show
# ...
render json: #organization, serializer: DetailedOrganizationSerializer
end
end
I have used AMS (0.8) with Rails 3.2.19 but one place where I really struggle with them is how to control whether serializers include their associations or not. I obviously use AMS to build JSON
Api's. Sometimes a serializer is the leaf or furthest out element and sometimes it's the top level and needs to include associations. My question is what is the best way to do this or is the solution I do below work (or is best solution).
I have seen some of the discussions but I find them very confusing (and version based). It's clear that for Serializer attributes or associations, there is an an include_XXX? method for each and you can return either a truthy or falsey statement here.
Here's my proposed code - it's a winemaker that has many wine_items. Is this how you would do this?
Model Classes:
class WineItem < ActiveRecord::Base
attr_accessible :name, :winemaker_id
belongs_to :winemaker
end
class Winemaker < ActiveRecord::Base
attr_accessible :name
has_many :wine_items
attr_accessor :show_items
end
Serializers:
class WinemakerSerializer < ActiveModel::Serializer
attributes :id, :name
has_many :wine_items
def include_wine_items?
object.show_items
end
end
class WineItemSerializer < ActiveModel::Serializer
attributes :id, :name
end
and in my controller:
class ApiWinemakersController < ApplicationController
def index
#winemakers=Winemaker.all
#winemakers.each { |wm| wm.show_items=true }
render json: #winemakers, each_serializer: WinemakerSerializer, root: "data"
end
end
I ran into this issue myself and this is the cleanest solution so far (but I'm not a fan of it).
This method allows you to do things like:
/parents/1?include_children=true
or using a cleaner syntax like:
/parents/1?include=[children], etc...
# app/controllers/application_controller.rb
class ApplicationController
# Override scope for ActiveModel-Serializer (method defined below)
# See: https://github.com/rails-api/active_model_serializers/tree/0-8-stable#customizing-scope
serialization_scope(:serializer_scope)
private
# Whatever is in this method is accessible in the serializer classes.
# Pass in params for conditional includes.
def serializer_scope
OpenStruct.new(params: params, current_user: current_user)
end
end
# app/serializers/parent_serializer.rb
class ParentSerializer < ActiveModel::Serializer
has_many :children
def include_children?
params[:include_children] == true
# or if using other syntax:
# params[:includes].include?("children")
end
end
Kinda hackish to me, but it works. Hope you find it useful!