Use pluck in Active Model Serializer - ruby-on-rails

I would like to use pluck method in Active Model Serializer for an object association:
Post has_many :comments
Is there a way to override
has_many :comments
in the serializer to use pluck(:id, :title) on the comments ?

You can use block with has_many to extend your association with methods. See comment "Use a block to extend your associations" here.
class Post < ActiveRecord::Base
has_many :comments do
def plucked()
select("id, title")
end
end
end
or other approach, from the same link can be, have your custom sql query when fetching comments from the database:
has_many :comments, :class_name => 'Comment', :finder_sql => %q(
SELECT id, title
FROM comments
WHERE post_id = #{id}
)
In rails documentation, It shows, there is an option :select, which can also be used for this purpose.

What I usually do in that situation, I have two different serializers CommentSerializer and CommentInfoSerializer. So CommentInfoSerializer only includes minimum attributes that I want to response in embedded attribute of their parent resource.
class CommentSerializer < ActiveModel::Serializer
attributes :id, :title, :body
end
class CommentInfoSerializer < ActiveModel::Serializer
attributes :id, :title
end
class PostSerializer < ActiveModel::Serializer
has_many :comments, serializer: CommentInfoSerializer
end

Related

Rails Active Model Json serializer: returning has_many record as has_one

I have a Active Model JSON Serializer for a model, which has a has_many relation, that I want to include in the JSON response.
I would like the record to be included as has_one instead of has_many record - to only include the first record:
class PersonSerializer < ActiveModel::Serializer
attributes :name, :symbol
has_many :stats
has_many :body_parts
end
Here, body_parts should be returned as has one :body_part. What is the best way to do that?
If you want to return only the first body_part and do that only in your serializer response, then better to define it as a method in PersonSerializer.
class PersonSerializer < ActiveModel::Serializer
attributes :name, :symbol
has_one :body_part, serializer: BodyPartSerializer
...
def body_part
self.object.body_parts.first
end
end
It assumes that you have a separate serialiser for BodyPart model.
Isn't it as simple as:
class Person
def body_part
body_parts.first
end
# or
has_one :body_part, -> { order(id: :asc) }
end
class PersonSerializer < ActiveModel::Serializer
attributes :name, :symbol
has_many :stats
has_one :body_part
end
In both cases you need to specific what exactly does it mean to be the first body part.

using ActiveModelSerializers and having children rendered with specific Seriazlier

I have the following relationships (using RoR 3.2.13 and ancestry 2.0.0) and REALLY need some help in configuring how the serializer renders with the MenuHeaderSerializer:
class Menu < ActiveRecord::Base
has_many :menu_headers
end
class MenuHeader < ActiveRecord::Base
has_ancestry # the nested relationship
has_many :items
belongs_to :menu
end
class Item < ActiveRecord::Base
belongs_to :menu_header
end
My serializers are pretty explanatory and look like this:
class MenuSerializer < ActiveModel::Serializer
attributes :id, :name, :menu_headers
has_many :menu_headers
end
class MenuHeaderSerializer < ActiveModel::Serializer
attributes :id, :name, :children # <- this needs to be called and wrapped in a MenuHeaderSerializer; it basically just dumps eveything like to_json
#has_many :items
end
So my call to children should return children using MenuHeaderSerializer. Does that make sense?
I have tried what I think are all of the variations like the following:
class MenuHeaderSerializer < ActiveModel::Serializer
attributes :id, :name, :sub # :children #, :sub
def sub
MenuHeaderSerializer.new(children)
#object.children
end
or trying to force children into using the MenuHeaderSerializer but am just at a loss. Any help would be appreciated.
Perhaps something like:
attributes :id, :name, :children serializer: MenuHeaderSerializer # doesn't work
thx
not sure about Ancestery but you can do
has_many :children, each_serializer: MenuHeaderSerializer

How to search belongs_to association attributes

I have two entities Posts and Comments associated as follows
class Post < ActiveRecord::Base
attr_accessible :title, :msg
has_many :comments
end
class Comment < ActiveRecord::Base
attr_accessible :msg
belongs_to :post
scope :search, lambda { |msg| where(arel_table[:msg].matches('%#{msg}%'))}
end
The scope :search now search only for comments(msg), I want to write another scope to search for posts(msg) in comments.
How to write this?
try the following (I favor class methods than scopes with lambdas because they look cleaner and are easier to read)
# comment.rb
def self.search(msg)
where(arel_table[:msg].matches('%#{msg}%'))
end
def self.post_search(msg)
joins(:post).where(Post.arel_table[:msg].matches("%#{msg}%"))
end

Active Model Serializers belongs_to

This question pertains to AMS 0.8
I've got two models:
class Subject < ActiveRecord::Base
has_many :user_combinations
has_ancestry
end
class UserCombination < ActiveRecord::Base
belongs_to :stage
belongs_to :subject
belongs_to :user
end
And two serializers:
class UserCombinationSerializer < ActiveModel::Serializer
attributes :id
belongs_to :stage
belongs_to :subject
end
class SubjectSerializer < ActiveModel::Serializer
attributes :id, :name, :description, :subjects
def include_subjects?
object.is_root?
end
def subjects
object.subtree
end
end
When a UserCombination is serialized, I want to embed the whole subtree of subjects.
When I try to use this setup I get this error:
undefined method `belongs_to' for UserCombinationSerializer:Class
I tried changing the UserCombinationSerializer to this:
class UserCombinationSerializer < ActiveModel::Serializer
attributes :id, :subject, :stage
end
In this case I get no errors, but the subject is serialized in the wrong way - not using the SubjectSerializer.
My questions:
Shouldn't I be able to use a belongs_to relation in the serializer?
If not - how can I get the wanted behaviour - embedding the subject tree using the SubjectSerializer?
This is not really elegant but it seems to be working :
class UserCombinationSerializer < ActiveModel::Serializer
attributes :id, :stage_id, :subject_id
has_one :subject
end
I don't really like calling has_one whereas it's actually a belongs_to association :/
EDIT: Disregard my comment about has_one/belongs_to ambiguity, the doc is actually pretty clear about it: http://www.rubydoc.info/github/rails-api/active_model_serializers/frames
In Active Model Serializer 0-10-stable, belongs_to is now available.
belongs_to :author, serializer: AuthorPreviewSerializer
belongs_to :author, key: :writer
belongs_to :post
belongs_to :blog
def blog
Blog.new(id: 999, name: 'Custom blog')
end
https://github.com/rails-api/active_model_serializers/blob/0-10-stable/docs/general/serializers.md#belongs_to
So you could do:
class UserCombinationSerializer < ActiveModel::Serializer
attributes :id
belongs_to :stage, serializer: StageSerializer
belongs_to :subject, serializer: SubjectSerializer
end
What if you try with something like this:
class UserCombinationSerializer < ActiveModel::Serializer
attributes :subject,
:stage,
:id
def subject
SubjectSerializer.new(object.subject, { root: false } )
end
def stage
StageSerializer.new(object.stage, { root: false } )
end
end

Adding many models to another model

I'm currently working on a small project using Ruby On Rails 3.2 to create a database that contains several unique Models. Each Model has many Elements and each Element has the potential to belong to many Models. I have been able to set up the models in the following manner:
class Model < ActiveRecord::Base
has_many :model_elements
has_many :elements, :through => :model_elements
attr_accessible :elements, :name, :notes, :ref
end
class Element < ActiveRecord::Base
has_many :model_elements
has_many :models, :through => :model_elements
attr_accessible :elementType, :name, :notes, :ref
validates_presence_of :name
end
class ModelElement < ActiveRecord::Base
belongs_to :Model
belongs_to :element
attr_accessible :model_id, :created_at, :element_id
end
My question is how do I add multiple Elements to a single Model? I've tried to find some documentation but I can't find anything. Currently I'm trying to do the following:
#model.elements = #element
Where #element is a predefined element however it's throwing the following error:
undefined method `each' for #<Element:0x007ff803066500>
Any help would be greatly appreciated.
Try
#model.elements << #element
collection.create(attributes = {})
Returns a new object of the collection type that has been instantiated with attributes, linked to this object through the join table, and that has already been saved.
#model.elements.create(:name => "example")
Amar's answer is correct. If you wanted you can simplify your models further by using the has_and_belongs_to_many association.
class Model < ActiveRecord::Base
has_and_belongs_to_many :elements, :join_table => :model_elements
end
class Element < ActiveRecord::Base
has_and_belongs_to_many :models, :join_table => :model_elements
end
#model.elements << #element

Resources