Rails Scope issue with ActiveRecord::Serializer - ruby-on-rails

I'm kind of new to rails and I just discovered serializers.
I proceed with the implementation for one of my model. I generated a serializer with
rails g serializer MyModel
Then in my controller, in my function that renders my data I do this :
render json: MyModel.where(...), each_serializer: MyModelSerializer, root: false
# note : that's the only line in my function
And finally my serializer :
class MyModelSerializer < ActiveModel::Serializer
attributes :id, :name, ... # all attributes in my model, I double-checked
end
The error i now get from the rails server is the following :
uninitialized constant MyModelController::MyModelSerializer
Am I missing something ? :(
Thanks for your help :)
By the way, I'll add that the function that is supposed to render json with the serializer is called with an ajax request from the view. Don't know if it changes things though...

Try to change this bit in your controller code:
each_serializer: ::MyModelSerializer
Two colon basically forces Ruby interpreter to look for MyModelSerializer class in the "root" and not within MyModelController. From your error message, that seems to be the problem.

Related

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 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

Rails - serializer passing parametr

I use active_model_serializers (0.9.2). I've been studying documention, stack and source code and still cant find some way to pass some parameter to serializer. The only one workaround is using default scope
def default_serializer_options
{
scope: some_param
}
end
#options, options orserialization_options seems to be not working for me.
This is the link which will help you with it link
First create a serializer in the serializer folder.
class AttachmentSerializer < ActiveModel::Serializer
attributes :id, :attachment_url
def attachment_url
object.attachment_url
end
end
Then in your controller you can do something like this
params.require(:model-name).permit( :attachment)

RocketPants and ActiveModelSerializers custom serializer

Damn, that's me again...
Quote from RocketPants git:
Support for active_model_serializers - If you want to use ActiveModelSerializers, we'll take care of it. Even better, in your expose call, pass through :serializer as expected and we'll automatically take care of invoking it for you.
So that's what I try to do:
def friends
#user = User.find_by_id(params[:id])
expose #user.friends.first(params[:limit].to_i), serializer: UserJustNameSerializer
end
And that's how I implement my serializers in user_serializer.rb:
class UserSerializer < ActiveModel::Serializer
....
end
class UserJustNameSerializer < ActiveModel::Serializer
attributes :id, :first_name, :last_name, :full_name, :avatar_thumb
def avatar_thumb
object.avatar.url(:thumb)
end
end
Using expose without serializer option is properly preparing JSON according to UserSerializer. Trying to use UserJustNameSerializer gives this error:
NameError (uninitialized constant Api::V1::UsersController::UserJustNameSerializer)
So the question is: how to properly show RocketPants the way to my serializer? Now it's trying to find it in UsersController.
So, as always, only after posting the question I get to answer =)
The solution is:
Place UserJustNameSerializer into its own file user_just_name_serializer.rb and use each_serializer: instead of serializer:, as I'm trying to serialize an array, not a single object.
For those who google: If I use serializer: UserJustNameSerializer on array, I get
NoMethodError (undefined method `read_attribute_for_serialization' for []:Array):

Rails: do non-ActiveRecord models need to include ActiveModel::Serializers, or just respond to #as_json?

Using Rails 3.2, I'm working on an API backed model (not ActiveRecord). I want to be able to call to_json on this model in Rails controllers. After reading through a bunch of the ActiveModel docs I'm still not clear on one thing:
Given a model like this:
class MyModel
attr_accessor :id, :name
def initialize(data)
#id = data[:id]
#name = data[:name]
end
def as_json
{id: #id, name: #name}
end
end
Should this work as expected, or do I also need to include ActiveModel::Serializers::JSON? I'm having a hard time figuring out where the as_json / to_json methods are normally defined and when Rails calls which ones automatically in different circumstances...
Thanks for any insight!
Yes this does work, however not quote as you've written in.
When you render json in a controller using
def action
render :json => #my_model
end
Then Rails will automatically call to_json on your object and as long as you've defined to_json this will work as expected.
If your controller uses the Rails 3 content negotiation shenanigans, ie.
class Controller < ApplicationController
respond_to :json, :html
def action
respond_with(#my_model)
end
Then you will need to override as_json on your class, but the method signature requires an optional hash of options to be compatible with ActiveSupport so in this case you want
def as_json(options={})
...
end
Alternatively If you include ActiveModel::Serializers::JSON into your Class and your class supports the attributes method that returns a hash of attrs and their values - then you'll get as_json for free - but without the control of the resultant structure that you have if you just override the method by hand.
Hope this helps.

Resources