I'm trying to serialize a collection of objects using the Array Serializer syntax.
ActiveModel::ArraySerializer.new(all, start_date: start_date, end_date: end_date, each_serializer: UserSerializer).to_json
I want to pass the start_date and end_date options so I can access it through serializer_options[:start_date] and serializer_options[:end_date]. When I puts out the serializer options though they are empty. I have serializer_options working when I use it through the render json call like this,
render json: @users, start_date: start_date, end_date: end_date
Please see https://github.com/rails-api/active_model_serializers/blob/master/lib/action_controller/serialization.rb#L38-L48 and perhaps http://www.benjaminfleischer.com/2015/06/02/understanding-rails-model-serializers/ for how AMS works
I'd recommend against calling ArraySerializer directly, in general. It's not the intended usage, AFAIK.
What are you trying to do that you want to pass start_data/end_date in the ArraySerializer? Maybe I can help you reach your goal?
If you want transient attributes on your serialized models, you can just add attr_accessors for that
I have a filterable/sortable table I'm getting json data served into from my api. I want to make it so they can export that data to csv. I have to do the csv stuff all on the backend so it is accessible via urls and not just the front end. At first I replicated the serializer with a to_csv method but I kept adding fields so I decided to serialize the data and then turn it into a csv so when I add a column I don't have to add it in two places.
The tables have date range input so I have to pass in dates form params to the serializer to get the right efficiency/productivity data. So those same params passed into the serializer for rendering the json to the page needs to get passed to the call to the json in the csv method.
Does all that make sense? I'm more than open to an alternate solution and unfortunately couldn't come up with one.
You want to generate a CSV form the JSON? That sounds like using a CSV renderer e.g. https://github.com/rails/rails/blob/4-2-stable/actionpack/lib/action_controller/metal/renderers.rb#L66-L128
It might help if you gave an example input and the desired output.
Here's some of my index controller code,
def index
@users = User.where(labor_enabled: true)
if params[:start_date].blank?
start_date = User::DEFAULT_START_DATE
else
start_date = Time.parse(params[:start_date])
end
if params[:end_date].blank?
end_date = User::DEFAULT_END_DATE
else
end_date = Time.parse(params[:end_date])
end
unless params[:search_term].blank?
@users = @users.where("lower(users.firstname) LIKE ? or lower(users.lastname) LIKE ?", "%#{params[:search_term].downcase}%", "%#{params[:search_term].downcase}%")
end
@users.to_csv(start_date, end_date)
respond_to do |format|
format.json {render json: @users, start_date: start_date, end_date: end_date, meta: {startDate: start_date, endDate: end_date, role_list: Role.select([:id, :name]).map {|e| [e.id, e.name]}, language_list: User::LANGUAGE_LIST, labor_task_list: LaborTask.where("maintenance is not true").select([:id, :name, :photo_file_name]).map {|e| {id: e.id, name: e.name, photo_file_name: e.photo_file_name}}}}
format.csv { send_data @users.to_csv(start_date, end_date) }
end
end
So I need that to_csv method to use the same serializer logic as the json serializer. Right now I'm kicking it to a to_csv method, which is doing this,
def self.to_csv(start_date=Time.now.midnight, end_date=Time.now)
csv = []
JSON.parse(ActiveModel::ArraySerializer.new(all, start_date: start_date, end_date: end_date, each_serializer: UserSerializer).to_json).each do |user|
csv << self::METRICS_TABLE_HEADERS.keys.map { |thing| user[thing]}
end
end
But the start_date and end_date aren't getting received by the serializer like they are in the json call.
Here's the serializer.
class UserSerializer < ActiveModel::Serializer
attributes :id, :delay_time, :current_task, :current_login, :firstname, :lastname, :efficiency, :hours, :photo_file_name, :daily_efficiency
def daily_efficiency
object.efficiency(Time.now.midnight, Time.now)
end
def efficiency
user_stats[:efficiency].round(2)
end
def hours
user_stats[:hours].round(2)
end
def user_stats
puts '==============='
ap serialization_options
puts '==============='
@stats ||= object.user_stats(serialization_options[:start_date], serialization_options[:end_date])
end
def current_login
object.current_task ? object.current_task.name : 'Not Logged In'
end
def delay_time
object.delay_time(serialization_options[:start_date], serialization_options[:end_date])
end
end
+1. I want to pass some params to seriallizer
in comment_seriallizer.rb
def initialize(object, options)
super
@current_user_id = options[:current_user_id]
end
controller
With single it work perfect
CommentSerializer.new(::Comment.first, {current_user_id: current_user.try(:id)})
But with array it not work.
ActiveModel::ArraySerializer.new(comments, current_user_id: current_user.try(:id), each_serializer: CommentSerializer)
puts options in function initialize => {:scope=>nil, :key_format=>nil, :only=>nil, :except=>nil, :polymorphic=>false, :namespace=>nil}
Hey ppl, just read the thread :smile:
What version of AMS are you using? If not 0.10.x scope might help you into passing parameters to serializer.
yeap. scope save my day :D thanks @joaomdmoura
Btw would be awesome if we could replicate this issue on StackOverflow to help others :smile:
I'm already using scope for current_user but I have to pass in start and end dates. So what is happening is there is a table of data and there's a start and end date filter. Once they change the dates it hits the api again with the new dates and needs to get the new data in json. What I'm doing is passing the params through the serialization options which works great but I'm trying to figure out how to pass the options in so I can get csv. And what I'm doing to make csv is I have a model method that takes the json serializer and then takes the processed result and converts it to csv.
@bf4 If I add a render of csv will render csv: @users just work with the other serializer? Or is there more to this?
What version of AMS are you using? Which versions of Rails/Ruby?
@bf4 .9-stable and I'm using rails 3.2.17. There were a lot of ways options were handled in various versions of AMS, and .9-stable allows you to pass things as serialization_options.
@jbhatab Have you tried to use .merge to merge the data you want, after serialization, with the dates you need
@joaomdmoura I have a unique scenario with this where I need to pass the params into the serializer for it to correctly serialize it. I could use attr_accessor but it makes a lot more sense to pass params from the front end to the serializer and then output the data based on the params.
In my case I have a date range filter and when I change the dates I need the serializer to output different efficiency and production values.
@jbhatab unfortunately I don't believe that we have a feature that would allow you to easily do this.
There are some workarounds, but nothing graceful, like pass the date together with the user as scope.
It just seems an edge case for me. :pensive:
It's totally fine. I really couldn't think of many other scenarios besides this but I ended up just making custom ruby objects.
Might be something to think about for 1.0 but I'm good!
Really appreciate the input.
Here is how you can pass parameters 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
Most helpful comment
+1. I want to pass some params to seriallizer
in comment_seriallizer.rb
controller
With single it work perfect
But with array it not work.
puts options in function initialize => {:scope=>nil, :key_format=>nil, :only=>nil, :except=>nil, :polymorphic=>false, :namespace=>nil}