I have updated active_model_serializer from 0.9.3 to 0.10.0 as I want to use the json_api adapter. Once updated, I no longer can use both my model serializer along with my custom serializer. Here's my backtrace:
[active_model_serializers] Rendered GroupedProjectsSerializer with
ActiveModelSerializers::Adapter::JsonApi (6.03ms)
Completed 500 Internal Server Error in 24ms (ActiveRecord: 0.3ms)
NoMethodError (undefined method `read_attribute_for_serialization' for
#<Hash:0x007f90cbed0ba8>):...
I have also tried including ActiveModel::Serialization in the custom serializer which then I get another error as below:
NoMethodError (undefined method `id' for #<GroupedItemSerializer:0x007fa47012ad38>):...
adding attributes :id doesn't resolve the issue though.
Here's my setup:
Initializer:
ActiveModel::Serializer.config.adapter = :json_api
Model Serializer:
class ItemSerializer < ActiveModel::Serializer
attributes :id, :code, :name, :item_type, ....
end
Custom Serializer:
class GroupedItemSerializer < ActiveModel::Serializer
def serializable_object(options = {})
#object.map do |group_key, items|
[group_key, serialized_items(items)]
end.to_h
end
private
def serialized_items(items)
items.map do |item|
ItemSerializer.new(item, root: false)
end
end
end
Controller:
#items = Item.all.group_by(&:item_type)
# using each_serializer also doesn't help as it only uses the
# GroupedItemserializer and not applying the ItemSerializer!
render json: #items, serializer: GroupedItemSerializer
Not sure if I'm missing something in the documentation, but I've tried all the possible ways to achieve this. Any help would be appreciated.
Related
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)
I get the following response by render json: Oj.dump(ReportTypeSymbol.all.to_a)
Current JSON format
report_type: "com_disagg",
symbol_code_id: {
$oid: "54bf7ff1506f6336e3020000"
}
Expected JSON format (do not nested the symbol_code_id)
report_type: "com_disagg",
symbol_code_id: "54bf7ff1506f6336e3020000"
Model definition
class ReportTypeSymbol
include Mongoid::Document
belongs_to :symbol_code
end
You can override as_json method in your model.
This is what I did. It works nested relations too.
Basically it's monkey-patching the Mongoid Documents and BSON objects.
Create a file Mongoid.rb in initializers (Rails)
module Mongoid
module Document
def as_json(options={})
attrs = super(options)
attrs['id'] = attrs.delete('_id').to_s
attrs
end
end
end
module BSON
class ObjectId
alias :to_json :to_s
alias :as_json :to_s
end
end
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):
While rendering xml for an object, I am getting the error
NoMethodError (undefined method `model_name' for OrderResponse:Class):
OrderResponse.rb
class OrderResponse
include ActiveModel::Serialization
attr_accessor :payload
end
In controller
def create
#order_response = OrderResponse.new
#order_response.payload = 12345
respond_to do |format|
format.xml { render :xml => #order_response }
end
end
I found other questions with similar titles while searching, according to that i modified 'respond_to' with 'respond_with' which inturns throws an error
undefinedMethod 'model_name' in OrderResponse
How to solve this?
I found an answer to this somewhere on stackoverflow and wish I could credit the source... This is my interpretation of it.
In Rails 3, if you have a resource listed in your routes which has a model .rb file but no active record table behind it, then you'll see this kind of error. This appeared for me as a form_for trying to reference a :controller and :action in this model. Perhaps it is related to Rails attempting to process associations for the model or something similar. Either way, this is new for me since I upgraded an application from Rails 2.3.8.
For me, the appears as:
undefined method `model_name' for SomeModel:Class
To fix it, at the top of the affected class add:
extend ActiveModel::Naming
include ActiveModel::Conversion
def persisted?
false
end
This has worked for me on two models like this.
You could try defining a class method by that name, which returns the name of the class:
def self.model_name; 'OrderResponse'; end
try including ActiveSupport::CoreExtensions::Module where model_name is defined ActiveSupport::CoreExtensions::Module
I'm returning to RoR after not using it for a few years and I'm trying to use ActiveModel to serialise a plain object to XML.
I'm doing the following, as per the comments in activemodel/lib/activemodel/serialization.rb:
class XmlError
include ActiveModel::Serializers::Xml
attr_accessor :code
attr_accessor :description
def attributes
#attributes ||= {'code' => 'nil', 'description' => 'nil'}
end
def initialize(error_code)
#code = error_code
#description = "blah"
self
end
end
I use this in a controller as:
render :xml => XmlError.new("invalid_login")
and I get the following stacktrace:
NoMethodError (undefined method `model_name' for XmlError:Class):
app/controllers/users_controller.rb:19:in `login'
app/controllers/users_controller.rb:5:in `login'
If create a model_name class method, I then get the following stacktrace:
NoMethodError (undefined method `element' for "XmlError":String):
app/controllers/users_controller.rb:19:in `login'
app/controllers/users_controller.rb:5:in `login'
It feels like I'm chasing my tail here. Have I just missed something simple in my class? I followed the example closely.
extend ActiveModel::Naming
is what you are looking for.
http://rdoc.info/github/lifo/docrails/master/ActiveModel/Naming
Why not sub-class ActiveModel::Base?