Rails - serializer passing parametr - ruby-on-rails

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)

Related

Url Helpers in ActiveModelSerializer 0.10.0?

I know this version is still not officially released but I was checking out rc3 today and I noticed that I can no longer use Rails url helpers inside my serializers. In version 0.8.x, I could do the following:
class BrandSerializer < BaseSerializer
attributes :id, :name, :slug, :state
attributes :_links
def _links
{
self: api_v1_company_brand_path(object.company_id, object.id),
company: api_v1_company_path(object.company_id),
products: api_v1_company_brand_products_path(object.company_id, object.id)
}
end
end
But this is a no go in the new version. What's the best way of resolving this so that I can keep my links in my serializer?
Edit:
For now I'm doing the following but would love to hear if there's a more idiomatic way.
class BaseSerializer < ActiveModel::Serializer
include Rails.application.routes.url_helpers
If you add this to your ApplicationController or even probably to the controller generating the response:
serialization_scope :view_context
You can then use the view_context in the serialiser to access the URL helpers (or any view methods really).
Example: view_context.api_v1_company_brand_path(object.company_id, object.id)
I thought this was probably cleaner than including all those URL helpers etc... into the serialiser class.
including the library which had been excluded (as you had done) would most definitely be the shortest route (outside of revising the gem itself, in terms of idiomacy)

How to define a Sparse Fieldset in a Rails request

Is there a simple way to implement requesting a Sparse Fieldset in a rails JSON request?
/some/endpoint.json?fields=id,name,favourite_colour
One solution I've found is to do it within a serialiser.
module V2
class BaseSerializer < ActiveModel::Serializer
self.root = true
def include?(field)
if #options.key?(:fields)
return #options[:fields].include? field.to_s
end
super field
end
end
end
In your controller you can do something like
render json: #sth, only: params[:fields].split(',').map(&:to_sym)
you should also wrap it in some strong params, to disallow non existing attributes
(but I doubt for it to be best possible solution)

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

Asset Pipeline in Active Model Serializers

I'm attempting to include an image asset pipeline url in my model serializer output by including ActiveView::Helpers:
class PostSerializer < ActiveModel::Serializer
include ActiveView::Helpers
attributes :post_image
def post_image
image_path "posts/#{object.id}"
end
end
The result is /images/posts/{id} rather than a valid path to the asset pipeline path, ie. /assets/images/posts/{id}. How can I include valid asset pipeline paths in my serializer output?
Maybe this could work:
def post_image
_helpers = ActionController::Base.helpers
_helpers.image_url "posts/#{object.id}"
end
(Very) late to the party, but you can solve the problem by adding this to your ApplicationController :
serialization_scope :view_context
and then in the serializer :
def post_image
scope.image_url('my-image.png')
end
Explanation : When your controller instanciates a serializer, it passes a scope (context) object along (by default, the controller itself I think). Passing the view_context allows you to use any helper that you would be able to use in a view.
So I have been struggling with this for a little bit today. I found a slightly less then ideal solution. The ActionController::Base.helpers solution didn't work for me.
This is certainly not the most optimal solution. My thinking is that the proper solution might be to add a 'set_configs' initializer to ActiveModelSerializer.
The ActionView::Helpers::AssetUrlHelper utilizes a function called compute_asset_host which reads config.asset_host. This property looks to be set in railtie initializers for ActionViews and ActionControllers. ActionController::RailTie
So I ended up subclassing the ActiveModel::Serializer and setting the config.asset_host property in the constructor, like so.
class BaseSerializer < ActiveModel::Serializer
include ActiveSupport::Configurable
include AbstractController::AssetPaths
include ActionView::Helpers::AssetUrlHelper
def initialize(object, options={})
config.asset_host = YourApp::Application.config.action_controller.asset_host
super
end
end
This got me most of the way. These helpers methods also use a protocol value; it can be passed in as a param in an options hash, a config variable, or read from the request variable. so I added a helper method in my BaseSerializer to pass the correct options along.
def image_url(path)
path_to_asset(path, {:type=>:image, :protocol=>:https})
end

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