Serializing a custom attribute - ruby-on-rails

I am using the Active Model Serializer gem for my application. Now I have this situation where a user can have an avatar which is just the ID of a medium.
I have the avatar info saved into Redis. So currently what I do to show the avatar at all in the serialized JSON, is this:
class UserSerializer < ActiveModel::Serializer
include Avatar
attributes :id,
:name,
:email,
:role,
:avatar
def avatar
Medium.find(self.current_avatar)[0]
end
#has_one :avatar, serializer: AvatarSerializer
has_many :media, :comments
url :user
end
I query Redis to know what medium to look for in the database, and then use the result in the :avatar key.
Down in the code there is also a line commented out, that was the only way I found on the https://github.com/rails-api/active_model_serializers/ page about using a custom serializer for something inside of serializer.
So to get to my problem. Right now the :avatar comes just like it is in the database but I want it to be serialized before I serve it as JSON.
How can I do that in this case?

You need to serialize Avatar Class:
class Avatar
def active_model_serializer
AvatarSerializer
end
end
Then you just use this way:
class UserSerializer < ActiveModel::Serializer
include Avatar
attributes :id,
:name,
:email,
:role,
:avatar
def avatar
# Strange you query another object
avatar = Medium.find(object.current_avatar).first
avatar.active_model_serializer.new(avatar, {}).to_json
end
has_many :media, :comments
url :user
end

According to the docs if you want a custom serializer you can just add:
render json: avatar, serializer: AvatarSerializer
or whatever your serializer name could be, here are the docs:
https://github.com/rails-api/active_model_serializers/blob/v0.10.6/docs/general/serializers.md#scope

Related

How to pass attributes in Serializer not in model in Rails (ActiveRecord)?

I am building a Rails backend that has Users, Sightings and Comments. The modelComment joins Sighting and User. I would like to pass the user's name or username along with the user_id which is an attribute of join table Comments in CommentSerializer to my front-end.
I can access this data using Active Record or Ruby methods but how do actually make this an attribute to be passed through Serializer?
Here's my CommentSerializer file:
class CommentSerializer < ActiveModel::Serializer
attributes :id, :body, :likes, :user_id
belongs_to :commentable, :polymorphic => true
belongs_to :sighting
has_many :comments, as: :commentable
end
add to your attributes :user_name for example and then add
def user_name
object.user.name
end
in your CommentSerializer class
So I had good luck with this method in my Serializer file to pass down this attribute:
def user_name
User.all.find { |f| f.id == object.user_id }.username
end

Active Model Serializer use no serializer

At times I'd like to use no serializer for a model, and other times I do. I have tried to request nil serializer, but it seems that a serializer is used regardless.
class API::FinancialDashboardSerializer < ActiveModel::Serializer
attributes :id, :name, :weeks_remaining
has_many :check_ins, serializer: nil
end
In this instance I'd like to return the association without any serializer, but it still uses the CheckInSerializer anyway.
Is there a way around this?
I think you could just do:
class API::FinancialDashboardSerializer < ActiveModel::Serializer
attributes :check_ins, :id, :name, :weeks_remaining
end
Or if that doesn't work:
class API::FinancialDashboardSerializer < ActiveModel::Serializer
attributes :check_ins, :id, :name, :weeks_remaining
def check_ins
object.check_ins.map(&:as_json)
end
end

Rails 4 + serialization: Nested models not showing

I am using the Active Model Serialization Gem to pull info for my API and my nested models are not working properly.
I have the following:
class API::ClientSerializer < ActiveModel::Serializer
attributes :name, :address
has_many :check_ins
end
class API::CheckInSerializer < ActiveModel::Serializer
attributes :id, :employee, :created_at, :type_of_weighin, :user_id
has_one :weigh_in
end
and while the check_ins show when I pull a client. The weigh_in is never included in the check_in. Is there something else I need to do?

Passing options to ActiveModel serializer

When using the serializer from the controller I can pass extra options to it like so
render json: user, some_option: 'foobar
Then I can reference some_option within the serializer as
serialization_options[:some_option]
But, if I call the serializer directly as
MySerializer.new(user, some_option: 'foobar')
I cannot get the extra options since serialization_options is an empty object.
For v0.9
You may call the following:
MySerializer.new(user).as_json({some_option: 'foobar'})
If you are doing that inside another serializer and you need to pass the scope and the current serialization_options as well, you can do this:
class MyParentSerializer
has_one :user
def user
MySerializer.new(object.user, { scope: scope }).as_json(serialization_options.merge({ some_option: 'foobar' }))
end
end
ActiveModel::Serializer's API has not really been consistent, in v0.9, however if you upgrade to v0.10, you could use the instance_options method to access the additional params. However, I'd be curious to learn how the objects were parsed in v0.9, though
Here is how you can pass parameters (options) from the parent serializer and show or hide attributes based on these parameters in the child serializer.
Parent serializer:
class LocationSharesSerializer < ActiveModel::Serializer
attributes :id, :locations, :show_title, :show_address
def locations
ActiveModelSerializers::SerializableResource.new(object.locations, {
each_serializer: PublicLocationSerializer,
params: {
show_title: object.show_title
},
})
end
end
Child serializer
class PublicLocationSerializer < ActiveModel::Serializer
attributes :id, :latitude, :longitude, :title, :directions, :description, :address, :tags, :created_at, :updated_at, :photos
def title
object.title if #instance_options[:params][:show_title]
end
end

Add new field to index.json in Rails 4

I would like to add a modified variable to my index.json.
views/posts/index.json.builder
json.array!(#posts) do |post|
post[:image_th] = post[:image].reverse.split('.', 2).join(".s").reverse
#this is the new line above
json.extract! post, :id, :title, :datum, :body, :image
#json.url post_url(post, format: :json)
end
So itt adds an 's' before ".jpg" in the string.
This gives error:
can't write unknown attribute `image_th'
How to add a field to index.json without creating a migration and accessing it from the database?
Try:
class Post < ActiveRecord::Base
# ...
def image_th
image.reverse.split('.', 2).join(".s").reverse
end
end
And then:
json.extract! post, :id, :title, :datum, :body, :image_th
EDIT:
Also the method would be probably slightly cleaner with:
def image_th
image.sub(/\.[^\.]+$/, 's\0')
end
If you don't need to persist it, you can use an attr_accessor :image_th in your Post model:
class Post < ActiveRecord::base
attr_accessor :image_th
end
Anyway that claims more to be a method than a field in your model

Resources