active model serializer multiple collection in one template - ruby-on-rails

I have this custom action which I want to save http trips to retrieve different collections with.
def dashboard
#projects = Project.all
#tasks = Task.all
respond_do do |format|
format.json {render {projects: #project, tasks: #tasks}, serializer: DashboardSerializer }
end
end
class DashboardSerializer < ActiveModel::Serializer
attributes :proejcts, :tasks
end
this gives me an error like this
undefined method `read_attribute_for_serialization' for #<Hash:0x007fb5d58108c0>
Is there any way that I can make arbitrary collection attributes in the active model serializer template as I can do in Rabl?
Thank you!

AMS has a distinction between single item serialization and item collection serialization.
I was getting the same error, my solution looked like this:
render json: #posts, each_serializer: FancyPostSerializer

Related

Rails active_model_serializer conditional include

When I have a has_many/belongs_to relationship in Rails 5 API with active_model_serializers I can pass the option to include a nested model.
def show
render json: #post, include: ['comments']
end
It's also possible to get multiple layers of nesting.
def show
render json: #post, include: ['comments', 'comments.comment_likes']
end
I can't find documentation anywhere about adding conditions to the include statement. Is it possible to do something like this?
def show
render json: #post, include: ['comments'] { top_contributor: true }
end
In master (which will soon become RC4), a PR has been merged that allows for the following at serializer level:
belongs_to :user, if: :include_user?
def include_user?
current_user.admin?
end

How to use parameters value from public_activity gem (Rails)?

I am building a Rails app. And in my app, there are Projects where users can "Follow". When a user follows one of the pages, he/she will get updates if somebody uploads/creates a folder/file.
Below is the screenshot when somebody just created a new folder:
And below is the code for "Create" action in my Folder controller:
def create
#folder = current_user.folders.where(project_id: params[:project_id]).create(folder_params)
respond_to do |format|
if #folder.save
#folder.create_activity :create, owner: current_user, :params => {
:project_id => proc {|controller, project| #folder.project.id},
:project_name => proc {|controller, project| #folder.project.name},
}
format.html { redirect_to #folder.project, notice: 'Folder was successfully created.' }
format.json { render :show, status: :ok, location: #folder }
else
format.html { render :new }
format.json { render json: #folder.errors, status: :unprocessable_entity }
end
end
end
As you can see :project_id and :project_name are the parameters for the public_activity when a new folder being created.
And below is the screenshot on how this parameters value looks like in the database after they were saved:
QUESTION:
So my question is, how do i use this parameters values in my activities_controller?
Here is the code for my activities controller right now:
class ActivitiesController < ApplicationController
def index
#activities = PublicActivity::Activity.order("created_at desc").where(owner_id: current_user.following_users, owner_type: "User")
end
end
Instead of using "owner_id:", I want to use the "project_id" value from parameters column. So how can i do this?
Thank you very much in advanced! :)
The parameters field contains a simple yaml dump, so not really easy to search efficiently.
A simple solution would be to use LIKE operator, for instance
PublicActivity::Activity.where("parameters LIKE '%project_id: #{#project.id}%'")
You might want to consider to add custom fields instead.
Thanks for the answer, but I got a better solution than using the parameters value or custom field.
Here is how my activities_controller looks like right now:
class ActivitiesController < ApplicationController
def index
activity_table = PublicActivity::Activity.arel_table
# We want to view all activity of folders related to projects we are follwing
folder_ids = Folder.where(project_id: current_user.following_projects.pluck(:id)).pluck(:id)
# Generate query for all activity related to folders we care about
folders_query = activity_table[:trackable_type].eq('Folder').and(
activity_table[:trackable_id].in(folder_ids)
)
# Generate query for all users that we follow
users_query = activity_table[:owner_id].in(current_user.following_users.pluck(:id))
activity_query = folders_query.or(users_query)
#activities = PublicActivity::Activity.where(activity_query)
end
end
By using this way, I could easily combine the activities from the "Users" and also from the "Projects" that the user follows.
You can modify it to add any other activities such as from the "Comments" or "Voting".
Hope this will help other people out there that are using public_activity gem! :)

Change ruby on rails controller to respond differently based on route nesting

Is it possible to have a controller that interacts in a standard way at both the top level and also the nested level? Or will static routes need to be configured?
When I visit the first address /list/:list_id/items I want it to follow the nested_index method to display only a subset of the listed items (The items that belong to the list).
http://localhost:3000/list/:list_id/items
When I visit the below (/items) address I want it to show the whole list of items.
http://localhost:3000/items
/app/controllers/items_controller.rb
def index
#Item = Item.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #Item }
end
end
def nested_index
#list = List.find(params[:list_id])
#items = #list.items.paginate(page: params[:page], per_page: 5)
respond_to do |format|
format.html # index.html.erb
format.json { render json: #list }
end
end
/config/routes.rb
AppName::Application.routes.draw do
resources :list do
resources :items
end
end
# Do I need to add further routes here?
Personally, I think you should split this out into two separate controllers.
The index method of your controller should be designed to do just one thing. In the case of your nested route it should be fetching all the items appropriate for the selected list and passing them to the appropriate view. In the other instance it is fetching all items and (probably) passing them to a completely different view.
It seems you're trying to get one controller to do the job of two, simply for the sake of the controller's name.
I'd suggest creating an apps_controller and use that to collect all your items and display them, and leave your items_controller for its nested use.
Remember you don't need to name a controller after the model it interacts with ... rather, you should name it after the function it is responsible for. A controller which receives an activation code for a user account might update an is_active boolean on a User model, but you would call this controller Activations since that is what it does.
If you have lots of overlap between controllers you can move their code into modules and then include those modules in both controllers. This way you can DRY up your code whilst keeping the logic separate where necessary.
Take a look at these links for some ideas on code extraction:
http://railscasts.com/episodes/398-service-objects
http://railscasts.com/episodes/416-form-objects
But before you start refactoring all of your code into modules ... consider whether it adds anything to your codebase. Does it make things simpler? Does it make things more readable? Does it save you anything other than typing out a few more lines? If there's no benefit to refactoring ... just don't do it.
#Jon is right. This should be split into several different controllers:
# app/controllers/items_controller.rb
class ItemsController < ApplicationController
# default RESTful actions to operate on lists, for example #index
def index
#Item = Item.all
respond_to do |format|
format.html
format.json { render json: #item }
end
end
end
# app/controllers/lists_controller.rb
class ListsController < ApplicationController
# default RESTful actions to operate on lists
end
# app/controllers/lists/items_controllers.rb
class Lists::ItemsController < ApplicationController
def show
#list = List.find(params[:list_id])
#items = #list.items.paginate(page: params[:page], per_page: 5)
respond_to do |format|
format.html
format.json { render json: #items }
end
end
end
Routes:
AppName::Application.routes.draw do
resources :items
resources :lists do
resources :items
end
end

Cannot access attr_accessor defined variables

I am using Thinking Sphinx to run searches and I get the appropriate ActiveRecord Models fine. The problem is, I want to create an appropriate link path and text on each model, then send the info to the browser in the form of JSON, via AJAX. I am using the following to build those link attributes:
In the controller:
class FindController < ApplicationController
def tag_results
#results = ThinkingSphinx.search(params[:terms])
#results.each do |result|
result.build_ajax_response
end
respond_to do |format|
format.html
format.json { render :json => #results }
end
end
end
In the model:
class TaggedItem < ActiveRecord::Base
attr_accessible :name
attr_accessor :search_link, :search_text
def build_ajax_response
self.search_link = Rails.application.routes.url_helpers.tagged_item_path(self.id)
self.search_text = self.name
end
end
The resulting json object doesn't have either of the search_* attributes listed, much less have a value for them. I've tried using #search_link as well as just search_link in the build_ajax_response method.
Am I doing this wrong? Could there be something else interfering?
Rails' default to_json doesn't know about those extra non active record attributes you've added. The easiest possible thing is probably to specify them as extra methods to include:
format.json { render :json => #results.to_json(:methods => [:search_link, :search_text]) }

Getting nested JSON output from Rails

Suppose I have a Rails app with two models Post and Comment. A post has_many comments and a comment belongs_to a post.
How can I override the respond_to function in the show action in order to get a JSON response containing both the Post properties and an array of Comment objects that it has?
Currently it is the vanilla Rails default:
# posts_controller.rb
def show
#post = current_user.posts.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #post }
end
end
You can do that using Active Record serialization method.
to_json
Below code should work.
format.json { render json: #post.to_json(:include => :comments) }
Try using active_model_serializers for json serialization. It is easy to include associated objects and also separates things by having a different file for serialization.
Example:
class PostSerializer < ApplicationSerializer
attributes :id, :title, :body
has_many :comments
end
You can override to_json in model or you can use Jbuilder or rabl.
Rails has provide the best way to respond :
Define respond_to on the top of your controller . like :
class YourController < ApplicationController
respond_to :xml, :json
def show
#post = current_user.posts.find(params[:id])
respond_with (#post)
end
end
For more info take a look on : http://davidwparker.com/2010/03/09/api-in-rails-respond-to-and-respond-with/

Resources