Load associations to one level while conditionally sideloading associations in Active model serializers - ruby-on-rails-3

AMS version 0.8.3,
I created a base_serializer.rb like this and extended the same.
class BaseSerializer < ActiveModel::Serializer
def include_associations!
if #options[:embed]
embed = #options[:embed].split(',').map{|item| item.strip.to_sym}
embed.each do |assoc|
include! assoc if _associations.keys.include?(assoc)
end
end
end
end
class EventSerializer < BaseSerializer
attributes :id, :name
has_many :organizers, serializer: OrganizerSerializer
has_many :participants, serializer: ParticipantSerializer
end
class OrganizerSerializer < BaseSerializer
attributes :id, :name
has_many :related, serializer: RelatedSerializer
end
class ParticipantSerializer < BaseSerializer
attributes :id, :name
has_many :related, serializer: RelatedSerializer
end
class RelatedSerializer < BaseSerializer
attributes :id, :name
has_many :something, serializer: SomethingSerializer
end
and the index method in EventsController is written as
# GET /events?embed=organizers,participants
def index
#events = Event.all
render json: #events, embed: params[:embed]
end
With this I can get the :id and :name of events, organizers and participants. But, I want the attributes of related association as well. I don't need details of something serializer. I want to go till this level for each association. How can I achieve that?

I ended up doing this to achieve the same.
class BaseSerializer < ActiveModel::Serializer
def include_associations!
#options[:embed_level] ||= 2
return unless #options.key?(:embed) && #options[:embed_level] != 0
embed = #options[:embed].split(',').map{|item| item.strip.to_sym}
embed.each do |assoc|
next unless _associations.key?(assoc)
assoc_serializer = serializer_for(assoc)
embed = #options[:embed]
embed_level = #options[:embed_level]
#options[:embed_level] = #options[:embed_level] - 1
#options[:embed] = assoc_serializer._associations.keys.join(",")
include! assoc
#options[:embed_level] = embed_level
end
end
def serializer_for(assoc)
serializer = _associations[assoc].options[:serializer]
return serializer if serializer
assoc.to_s.classify.concat("Serializer").constantize
end
end
Ref: Github Issue Link
Special Thanks to Yohan Robert!!!

Related

How to create nice forms with active_scaffold gem on Rails 3

How to override Active Scaffold form fields for date or time?
(datepicker and calendar_date_select didn't work for me, probably
because I'm using the activescaffold gem)
How to override Active Scaffold form to select from a list of resources in the
database?
Thanks.
I was struggling this question until I figured it out. Here's an example:
class Player < ActiveRecord::Base
belongs_to :game
attr_accessible :name
end
class Game < ActiveRecord::Base
has_many :players
attr_accessible :thedate, :thetime, :winnername
end
class GamesController < ApplicationController
active_scaffold :game do |conf|
# do nothing in this example
end
end
module GamesHelper
# date select
def game_thedate_form_column (record, options)
date_select :record, :thedate, options
end
# time select
def game_thetime_form_column (record, options)
time_select :record, :thetime, options
end
# select from database resources
def game_winnername_form_column (record, options)
select_tag :winnername, options_for_select(get_players_names_arr(record)), options
end
def get_players_names_arr(game)
names = []
game.players.each do |player|
names << player.name
end
names
end
end

Access parent of has_many relationship

Is there a way to access the parent of a polymorphic model in Mongoid 3?
I have this relationship
class Project
...
field "comments_count", :type => Integer, :default => 0
has_many :comments, :as => :commentable
...
end
class Comment
...
field "status"
belongs_to :commentable, :polymorphic => true
before_validation :init_status, :on => :create
after_create :increase_count
def inactivate
self.status = "inactive"
decrease_count
end
private
def init_status
self.status = 'active'
end
def increase_count()
#commentable.inc(:comments_count, 1)
end
def decrease_count()
#commentable.inc(:comments_count, -1)
end
...
end
I'd like to be able to update the comments_count in the parent relationship when the comment is inactivated since doing a count() on the child is very expensive (and I'd need to do that a lot in the app). I have the increase_count working, but I can't access #commentable in decrease_count (#commentable = nil). Any ideas?
The # in #commentable is unnecessary because its not an instance variable of your model. So:
def increase_count()
commentable.inc(:comments_count, 1)
end
def decrease_count()
commentable.inc(:comments_count, -1)
end
should do the trick.

How to restrict Sunspot search with nested models?

I want to filter the Sunspot search results with with(:is_available, true).
This is working with the User model, but I can't make it work with the Itinerary model.
app/controllers/search_controller.rb:
class SearchController < ApplicationController
before_filter :fulltext_actions
private
def fulltext_actions
#itineraries = do_fulltext_search(Itinerary)
#users = do_fulltext_search(User)
#itineraries_size = #itineraries.size
#users_size = #users.size
end
def do_fulltext_search(model)
Sunspot.search(model) do
with(:is_available, true)
fulltext params[:search]
end.results
end
end
app/models/user.rb:
class User < ActiveRecord::Base
has_many :itineraries, :dependent => :destroy
searchable do
text :first_name, :boost => 3
text :last_name, :boost => 3
text :status
boolean :is_available, :using => :available?
end
def available?
!self.suspended
end
end
app/models/itinerary.rb:
class Itinerary < ActiveRecord::Base
belongs_to :user
searchable do
text :title, :boost => 3
text :budget
text :description
boolean :is_available, :using => :available?
end
def available?
!self.user.suspended
end
end
Any ideas?
Thanks!
Well, my real problem was the indexation.
When I update the User model, I set a flag (like user_instance.update_index_flag = true) in my controller.
In the User model:
attr_accessor :update_index_flag
after_save :reindex_sunspot
def reindex_sunspot
if self.update_index_flag
Sunspot.index(self.itineraries.to_a)
end
end
That's it...

Rails 3: Find parent of polymorphic model in controller?

I'm trying to find an elegant (standard) way to pass the parent of a polymorphic model on to the view. For example:
class Picture < ActiveRecord::Base
belongs_to :imageable, :polymorphic => true
end
class Employee < ActiveRecord::Base
has_many :pictures, :as => :imageable
end
class Product < ActiveRecord::Base
has_many :pictures, :as => :imageable
end
The following way (find_imageable) works, but it seems "hackish".
#PictureController (updated to include full listing)
class PictureController < ApplicationController
#/employees/:id/picture/new
#/products/:id/picture/new
def new
#picture = imageable.pictures.new
respond_with [imageable, #picture]
end
private
def imageable
#imageable ||= find_imageable
end
def find_imageable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
end
Is there a better way?
EDIT
I'm doing a new action. The path takes the form of parent_model/:id/picture/new and params include the parent id (employee_id or product_id).
I'm not sure exactly what you're trying to do but if you're trying to find the object that 'owns' the picture you should be able to use the imageable_type field to get the class name. You don't even need a helper method for this, just
def show
#picture = Picture.find(params[:id])
#parent = #picture.imagable
#=> so on and so forth
end
Update
For an index action you could do
def index
#pictures = Picture.includes(:imagable).all
end
That will instantiate all 'imagables' for you.
Update II: The Wrath of Poly
For your new method you could just pass the id to your constructor, but if you want to instantiate the parent you could get it from the url like
def parent
#parent ||= %w(employee product).find {|p| request.path.split('/').include? p }
end
def parent_class
parent.classify.constantize
end
def imageable
#imageable ||= parent_class.find(params["#{parent}_id"])
end
You could of course define a constant in your controller that contained the possible parents and use that instead of listing them in the method explicitly. Using the request path object feels a little more 'Rails-y' to me.
I just ran into this same problem.
The way I 'sort of' solved it is defining a find_parent method in each model with polymorphic associations.
class Polymorphic1 < ActiveRecord::Base
belongs_to :parent1, :polymorphic => true
def find_parent
self.parent1
end
end
class Polymorphic2 < ActiveRecord::Base
belongs_to :parent2, :polymorphic => true
def find_parent
self.parent2
end
end
Unfortunately, I can not think of a better way. Hope this helps a bit for you.
This is the way I did it for multiple nested resources, where the last param is the polymorphic model we are dealing with: (only slightly different from your own)
def find_noteable
#possibilities = []
params.each do |name, value|
if name =~ /(.+)_id$/
#possibilities.push $1.classify.constantize.find(value)
end
end
return #possibilities.last
end
Then in the view, something like this:
<% # Don't think this was needed: #possibilities << picture %>
<%= link_to polymorphic_path(#possibilities.map {|p| p}) do %>
The reason for returning the last of that array is to allow finding the child/poly records in question i.e. #employee.pictures or #product.pictures

Using after_create

I have a model, Category. And I want to create an new default sub_category when ever the category is created. But I'm not sure how to do it. Here is what I have.
class Category < ActiveRecord::Base
attr_accessible :title, :position
has_many :sub_categories
after_create :make_default_sub
def make_default_sub
#Sub_Categories.new( :title=>' ');
end
end
Why not to use ancestry gem? In the future if you will have more subcategories, it will be easier to manage them.
For example in your case:
class Category < ActiveRecord::Base
attr_accessible :title, :position
has_ancestry
after_create :create_default_subcategory
def make_default_sub
children = self.children.new
children.title = ''
children.position = 1 # or autogenerated
children.save!
end
end
But can you explain, why do you need such a strange default behaviour?
Thanks