-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optional attributes / Passing arbitrary params to serializer #599
Comments
This feature will ensure more flexibility - like pagination in embedded objects. class ConversationSerializer < ActiveModel::Serializer
params :show_details, :page, :per_page
def attributes
if @show_details
super.merge(messages: object.messages.page(@page).per(@per_page))
else
super.merge(last_message: object.last_message)
end
end
end
# controller
render json: @conversation, serializer_params: { show_details: true, page: params[:page], per_page: params[:per_page] } |
in case of full/detail view I would suggest using two serializers with a common shared parent if needed and then do : render json: @conversation, serializer: ConversationDetailSerializer Do you have any other use cases? |
@tchak I don't like that approach (as mentioned in #552), because it requires at least 3 classes to achieve DRY-ness just to handle one optional attribute. It quickly gets out of control when you have more optional behaviors. Let's assume that you have a user class, which has limited accessibility for the public profile, and expose more data for your friends. The class also has "following" and "followed" flag, which represents relationship, but those relationship attirbutes won't be included if it was called from yourself, or you're not logged in. When it's called from yourself, the class includes "email_confirmed", to display alert if the email hasn't been confirmed yet. class UserSerializer < ActiveModel::Serializer
attributes :id, :username, :created_at, ...
params :authorization, :include_details
def attributes
base_attributes = @include_details ? super.merge(details: object.details) : super
case @authorization
when :public
base_attributes
when :myself
base_attributes.merge(email_confirmed: object.email_confirmed?)
when :loggedin
base_attributes.merge(following: scope.following?(object), followed: scope.followed?(object))
when :friends
base_attributes.merge(following: scope.following?(object), followed: scope.followed?(object), friends_only_data: object.friends_only_data)
end
end
end
# controller
render json: @user, serializer_params: { include_details: true, authorization: :friends } With this fairly simple example, you already need 9 classes if you go with the inheritance way. We need a way to manage combinatorial explosion. |
Yet another example, a picture model using paperclip, that automatically choose the best thumbnail for a given numeric size. class Picture < ActiveRecord::Base
has_attached_file :data, { tiny: '32x32^', small: '48x48^', ... }
end
class PictureSerializer < ActiveModel::Serializer
attributes :url, :content_type
params :size
def url
object.data.url(thumbnail_key)
end
def thumbnail_key
case @size
when 0..32
:tiny
when 33..48
:small
...
else
:original
end
end
end
# controller
render json: @pictures, serializer_params: { size: 100 } One nice thing about this design is that controller's render json: @pictures, serializer_params: params.permit(:size) |
Another way of doing it might be accepting a serializer instance rather than a class: render json: @pictures, serializer: PictureSerializer.new(params.permit(:size)) |
Just noticed this, and think this addition is needed for flexibility. I love this gem, but it would be helpful to easily bring in data that is indirectly related to the model. For example, imagine showing a user a list of his or her clubs, and showing the number of users in each club. It is easy to get the number of users for each club like such: The following is a solution, but would lead to N + 1 Queries. Ultimately, one would like to be able to pass in the value from the outside.
Also, one could include this information in the |
I have a scenario where I need params as well. I need to get the amount of weight a user lost based on a date range. I can't think of any other way to do this without passing in params. |
@jbhatab, I found a solution, which I feel is a tad hacky, but works. If you reference my post, right above yours, you see that I need the
Then, before you try to serialize it, you would take your object, Once you have that, in your serializer, do something like:
|
@dilizarov @jbhatab It is demonstrated in my original post. 😄 Still, we need a way to separate view concern / serializer concern from models. |
@kenn Oh, I didn't notice that you already showed that method. I think we're all in agreement though. Params would be awesome. |
@dilizarov @kenn Thanks for the temp fix. The documentation on this issue is all over the place. The github has closed issues that seem like it fixed it, open issues that say it's a problem, and stack overflow posts that say it's answered but it's not. Just letting you guys know. What is the guy in this post referencing? Isn't this "params"? Because it doesn't work. http://stackoverflow.com/questions/23347587/how-to-pass-parameters-to-activemodel-serializer |
Also can't I just do the following if I'm using attr_accessor instead of the attributes super thing. attributes :number_of_users That should get the correct value and put it in the serialized data correctly. |
Looks like a patch has been merged to master. #679 I would prefer something shorter than I'll try to cook up a pull request if we like |
@jbhatab Sure, but for API requests that don't need the |
ok I see. And I tried the whole serialization_options and that didn't work. Just letting you know. I was using version .90 |
For some reason the master branch says I'm on version .90, but I just switched explicitly to the '0-9-stable' branch and serialization_options works now. Just wanted to let you guys know. Here's the line in my gem file,
|
It's probably because you haven't updated in a while. Master used to be 0.9.0. |
I only started this project 2 weeks ago. I was using master, but serialization_options doesnt work on master. What version is master? |
@jbhatab I had the same problem; and ended up downgrading to 0.8.x and used @options instead. I had another issue with 0.9.x anyway with infinite loops. @steveklabnik even called 0.8.x a "dead end" here because 0.10.x will be based on 0.9.x: |
@kriskhaira He's calling
|
This is correct. 0.10 is based on 0.8, not 0.9. |
@steveklabnik @manuelmeurer Yeah you're right |
👍 |
Is there a recommended way to do this with |
Never mind, found it under |
@jszwedko do you have an example of what you did? This issue has great discussion in it.. |
Sure thing, I did something like: PostController ...
def show
render json: @post, user_id: 1234
end
... PostSerializer ...
def my_comments
Comments.where(user_id: instance_options[:user_id], post_id: object.id)
end
... |
ah, @jszwedko awesome, very clever use of all options going to the serializer unless the adapter |
Thanks @jszwedko - exactly what I needed! |
Any solution for
|
@jszwedko I think everyone would 💯 if you were to write a documentation PR for this... 😄 or maybe even with tests :) |
I too receive |
@cickes |
While instance_options is a method that I think works great, I'd like to say that I really enjoy the attr_accessor way of doing things as well. For example, in a feed of posts, I need to mark if a user has liked each post. After fetching the feed's posts, I then do something like |
Thanks @beauby. Changing from |
@dilizarov your case is one of the "legit" use cases of I consider serializer as one of the presenter / decorator patterns, and the view (serializer) concerns should be self-contained. And considering how often we use them, repetitive |
I also tried instance_options (without the @) and it still didn't work. Undefined method or variable |
(from #552) I just realized that AMS is in flux. But I'd throw in my issue (based on 0.9), anyway.
We have a master-detail view where the master shows a list of conversations with the last message included, and the detail displays one conversation with all messages.
One way to do it is:
But this feels wrong on two fronts:
show_details
. There should be a way to directly pass the hint from controller to serializer, not through model.conversations.each{|i| i.show_details = true }
. The hint should be stored at the array level, not at the item level.For those reason, I would suggest that we enable to pass arbitrary parameters to the serializer, from controller.
and pass down the params to each item, when the target was an array.
That way, we don't have to alter the model and separation can be done nicely. What do you think?
The text was updated successfully, but these errors were encountered: