my current json output is "id":3,"name":"test", and I need the 3 to be "3".
How would I go about doing this in rails?
def search
#tags = Tag.where("name like ?", "%#{params[:q]}%")
respond_to do |format|
format.json { render :json => #tags.to_json(:only => [:id, :name]) }
end
end
Sergio's solution will work. However, if you're doing this in more than one place, I would suggest overriding Rails' built in function as_json.
In your Tag model:
def as_json(options={})
options[:id] = #id.to_s
super(options)
end
Your controller method will remain unchanged. This is untested, but should work.
Something like this:
format.json do
tags = #tags.to_json(:only => [:id, :name])
render :json => tags.map{|t| t['id'] = t['id'].to_s; t}
end
This was the only solution that worked for me:
def search
#tags = Tag.where("name like ?", "%#{params[:q]}%")
respond_to do |format|
format.json { render :json => #tags.map {|t| {:id => t.id.to_s, :name => t.name }} }
end
end
Related
First of all, this is my first experience with ruby. At this moment, I'm creating tests for the a Controller called Exporter in my application. The method of the Controller I want to test is this:
def export_as_json(equipments)
equipments_json = []
equipments.each {|equipment|
equipment_json = {
:id => equipment.id,
:title => equipment.title,
:description => equipment.description,
:category => equipment.category_id
}
equipments_json << equipment_json
}
respond_to do |format|
format.json { render :json =>equipments_json }
end
end
So, when I try to create a request for this method using this:
RSpec.describe ExporterController, type: :controller do
get '/equipments/all', headers: { 'CONTENT_TYPE' => 'application/json' }, format: :json
expect(response.response).to eq(200)
end
inside the exporter_controller_test.rb file I'm receiving this error:
NoMethodError: undefined method `get' for RSpec::ExampleGroups::ExporterController:Class
This is one of the problems pretty much every one runs into at least once ;)
Step 1: Read the error message very carefully
NoMethodError: undefined method 'get' for RSpec::ExampleGroups::ExporterController:Class
Step 2: Remember the wording NoMethodError: undefined method get for RSpec::ExampleGroups::XXX:Class
Step 3: Solve it by making it an actual example
RSpec.describe ExporterController, "#index", type: :controller do
it "should respond with status: 200" do
get '/equipments/all', headers: { 'CONTENT_TYPE' => 'application/json' }, format: :json
expect(response.response).to eq(200)
end
end
You were simply missing the it block.
I know this is not an answer to your question. But, since you mentioned that you're new to ruby, I thought I would point out that your code could be simplified and prettified a bit.
First, you don't need to do equipments_json = [] and then equipments.each. That's what map is for:
def export_as_json(equipments)
equipments_json = equipments.map{|equipment| {
:id => equipment.id,
:title => equipment.title,
:description => equipment.description,
:category => equipment.category_id
}
}
respond_to do |format|
format.json { render :json =>equipments_json }
end
end
Now, that hash you're putting into equipments_json is just a subset of equipment's attributes. So, use slice there to get the attributes you want:
def export_as_json(equipments)
equipments_json = equipments.map{|equipment| equipment.attributes.slice('id','title','description','category_id')}
respond_to do |format|
format.json { render :json =>equipments_json }
end
end
That map line is still a little long, so, maybe put it into a do block (like you had with each):
def export_as_json(equipments)
equipments_json = equipments.map do |equipment|
equipment.attributes.slice('id','title','description','category_id')
end
respond_to do |format|
format.json { render :json =>equipments_json }
end
end
And personally, I like using symbols instead of strings as my keys, so use with_indifferent_access so that you can use symbols:
def export_as_json(equipments)
equipments_json = equipments.map do |equipment|
equipment.attributes.with_indifferent_access.slice(:id, :title, :description, :category_id)
end
respond_to do |format|
format.json { render :json =>equipments_json }
end
end
That line got a little to long again, so I think I would go ahead and wrap it:
def export_as_json(equipments)
equipments_json = equipments.map do |equipment|
equipment.
attributes.
with_indifferent_access.
slice(:id, :title, :description, :category_id)
end
respond_to do |format|
format.json { render :json =>equipments_json }
end
end
Now, there are some different ways to get those attributes you want (e.g., modifying to_json). But, this will get the job done.
Hope that helps and good luck!
PS: I just noticed in your original hash, you're doing:
:category => equipment.category_id
if that's not a typo and you really want category instead of category_id, then you could do something like:
def export_as_json(equipments)
equipments_json = equipments.map do |equipment|
equipment.
attributes.
with_indifferent_access.
slice(:id, :title, :description).
merge!(category: equipment.category_id)
end
respond_to do |format|
format.json { render :json =>equipments_json }
end
end
Also, the convention for hashes is to do title: equipment.title. :title => equipment.title absolutely works, but is not the current convention. This is a style guide for ruby, in case it helps.
I want to send the count value,for count the post i am using thumbs up gem in ROR.
Now i want to send the count in json,the vote as post action in def show
def index
#posts = Post.all
respond_with(#posts) do |format|
format.json { render json: #post_names = {:post => #posts.as_json(:only=> [:content, :title]) } }
end
end
I want to send the count value using json,because i want to show that count value in my client side.
You can send vote count by this way. I assume something like this can work..
def index
#posts = Post.all
respond_with(#posts) do |format|
format.json { render :json => #post_names = {:post => #posts.map {|t| {:title => t.title, :content => t.content, :count => t.votes_for }} } }
end
end
Since you're working on the controller, you might find it helpful to look at the render section of the Rails documentation.
So I would like to just get back the :id, :name attributes of my #neighborhood object in my json response.
This is my action in my controller:
def autocomplete_neighborhood_name
#neighborhood = Neighborhood.select("id, name").where("name LIKE ?", "#{params[:name]}%").order(:name).limit(10)
respond_to do |format|
format.json { #neighborhood :only => [:id, :name]}
end
end
I am getting a syntax error on the format.json... line.
How do I do accomplish what I want?
Thanks.
Edit 1
My real goal is to try and refactor this code, to use format.json and use the newer methods of Rails 3.2.x:
def autocomplete_neighborhood_name
respond_with(
Neighborhood.
select("id, name").
where("name LIKE ?", "#{params[:name]}%").
order(:name).
limit(10).
as_json(:only => [:id, :name]))
end
If you have any other suggestions for how I might do this better, I would appreciate the feedback.
Try this:
format.json { render json: #neighborhood , :only => [:id, :name] }
I am new to rails so could use some help here. I have followed several tutorials to create a blog with comments and even some of the AJAX bells and whistles and I am stuck on something that I hope is easy. The default display for both blogs and comments is to list the oldest first. How do I reverse that to show the most recent entries and the most recent comments at the top. Don't really know if this is a function of the controller or model. I have done some customization so here is the code for the controller .rb files if it helps.
COMMENTS CONTROLLER
class CommentsController < ApplicationController
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create!(params[:comment])
respond_to do |format|
format.html { redirect_to #post}
format.js
end
end
end
POSTS CONTROLLER
class PostsController < ApplicationController
before_filter :authenticate, :except => [:index, :show]
# GET /posts
# GET /posts.xml
def index
#posts = Post.all(:include => :comments)
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #posts }
format.json { render :json => #posts }
format.atom
end
end
# GET /posts/1
# GET /posts/1.xml
def show
#post = Post.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #post }
end
end
# GET /posts/new
# GET /posts/new.xml
def new
#post = Post.new
respond_to do |format|
format.html { redirect_to #post}
format.js
end
end
# GET /posts/1/edit
def edit
#post = Post.find(params[:id])
end
# POST /posts
# POST /posts.xml
def create
#post = Post.new(params[:post])
respond_to do |format|
if #post.save
flash[:notice] = 'Post was successfully created.'
format.html { redirect_to(#post) }
format.xml { render :xml => #post, :status => :created, :location => #post }
else
format.html { render :action => "new" }
format.xml { render :xml => #post.errors, :status => :unprocessable_entity }
end
end
end
# PUT /posts/1
# PUT /posts/1.xml
def update
#post = Post.find(params[:id])
respond_to do |format|
if #post.update_attributes(params[:post])
flash[:notice] = 'Post was successfully updated.'
format.html { redirect_to(#post) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #post.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.xml
def destroy
#post = Post.find(params[:id])
#post.destroy
respond_to do |format|
format.html { redirect_to(posts_url) }
format.xml { head :ok }
end
end
private
def authenticate
authenticate_or_request_with_http_basic do |name, password|
name == "admin" && password == "secret"
end
end
end
As jtbandes pointed out, to reverse the posts in the index, you'd change the line in your index action to read:
#posts = Post.all(:include => :comments, :order => "created_at DESC")
In order to reverse the listing of your comments, there are two possibilities.
Option 1: In your post model you can declare your relationship like so:
class Post < ActiveRecord::Base
has_many :comments, :order => "created_at DESC"
end
Option 2: In your index view, simply reverse the array of each post's comments before displaying them:
<% #posts.each do |post| %>
<%= render :partial => post %>
<%= render :partial => post.comments.reverse %>
<% end %>
The options have different use cases. In option 1, you're saying that throughout your entire application, any time you refer to the comments on a post, those comments should be retrieved from the database in the specified order. You're sort of saying that this is an intrinsic property of comments in your application - posts have many comments, which are by default ordered newest first.
In option 2, you're simply reversing the comments in the index page before they're rendered. They were still retrieved in the original order (oldest first) from the database, and they'll still appear in that order anywhere else you access the comments of a post in your application.
If you're looking for a more generic way to reverse the order of the .each method, Rails has the .reverse_each method. Like so:
<% #posts.reverse_each do |post| %>
<%= render :partial => post %>
<%= render :partial => post.comments.reverse %>
<% end %>
#posts = Post.find(:all, :include => :comments, :order => "published_at DESC")
It looks like you can reverse the order using find: something like Post.find(:all, :order => "created_at DESC"). The same should apply to comments.
.reverse_each method bumping with will_paginate
here is the solution
#posts = Post.all.paginate(:order => "created_at DESC",:page => params[:page],:per_page => 5)
try use: reverse_order
Client.where("orders_count > 10").order(:name).reverse_order
this will execute the SQL:
SELECT * FROM clients WHERE orders_count > 10 ORDER BY name DESC
If no ordering clause is specified in the query, the reverse_order orders by the primary key in reverse order.
Client.where("orders_count > 10").reverse_order
which will execute:
SELECT * FROM clients WHERE orders_count > 10 ORDER BY clients.id DESC
http://edgeguides.rubyonrails.org/active_record_querying.html#reorder
I'd love to use render :json but it seems its not as flexible. Whats the right way to do this?
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #things }
#This is great
format.json { render :text => #things.to_json(:include => :photos) }
#This doesn't include photos
format.json { render :json => #things, :include => :photos }
end
I've done something similar with render :json. This is what worked for me:
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #things.to_json(:include => { :photos => { :only => [:id, :url] } }) }
end
I guess this article can be useful for you - Rails to_json or as_json? by Jonathan Julian.
The main thought is that you should avoid using to_json in controllers. It is much more flexible to define as_json method in your model.
For instance:
In your Thing model
def as_json(options={})
super(:include => :photos)
end
And then you can write in your controller just
render :json => #things
Managing complex hashes in your controllers gets ugly fast.
With Rails 3, you can use ActiveModel::Serializer. See http://api.rubyonrails.org/classes/ActiveModel/Serialization.html
If you're doing anything non-trivial, see
https://github.com/rails-api/active_model_serializers. I recommend creating separate serializer classes to avoid cluttering your models and make tests easier.
class ThingSerializer < ActiveModel::Serializer
has_many :photos
attributes :name, :whatever
end
# ThingsController
def index
render :json => #things
end
# test it out
thing = Thing.new :name => "bob"
ThingSerializer.new(thing, nil).to_json
format.json { render #things.to_json(:include => :photos) }
in case of array what I done is
respond_to do |format|
format.html
format.json {render :json => {:medias => #medias.to_json, :total => 13000, :time => 0.0001 }}
end