I found how to render ActiveRecord objects in Rails 3, however I cannot figure out how to render any custom objects. I am writing an app without ActiveRecord. I tried doing something like this:
class AppController < ApplicationController
respond_to :json
...
def start
app.start
format.json { render :json => {'ok'=>true} }
end
end
When you specify a respond_to, then in your actions you would make a matching respond_with:
class AppControlls < ApplicationController
respond_to :json
def index
hash = { :ok => true }
respond_with(hash)
end
end
It looks like you're conflating the old respond_to do |format| style blocks with the new respond_to, respond_with syntax. This edgerails.info post explains it nicely.
class AppController < ApplicationController
respond_to :json
def index
hash = { :ok => true }
respond_with(hash.as_json)
end
end
You should never use to_json to create a representation, only to consume the representation.
format.json { render json: { ok: true } } should work
This was very close. However, it does not automatically convert the hash to json. This was the final result:
class AppControlls < ApplicationController
respond_to :json
def start
app.start
respond_with( { :ok => true }.to_json )
end
end
Thanks for the help.
For those getting a NoMethodError, try this:
class AppController < ApplicationController
respond_to :json
...
def start
app.start
render json: { :ok => true }
end
end
Related
My goal is an output like this (for each attachment):
url:
"/uploads/attachment/picture/15/5ee306c9-e263-466b-b56d-1c7c9d2ae17b.jpg"
What I have at the moment:
attachments_controller.rb
class AttachmentsController < ApplicationController
before_action :logged_in_user
def index
#attachments = current_user.attachments.all
respond_to do |format|
format.json do
render :json => #attachments.each{ |o| o.picture.url }
end
end
end
...
Try
respond_to do |format|
format.json do
render :json => #attachments.map { |o| { url: o.picture.url } }
end
end
I am a student and I got the memo (without explanation) that
my following code is bugged and can be much better. How would you improve my controller#newname method? Thank you for your time!
class ReviewController < ApplicationController
def index
#reviews = Review.all.order(created_at: :desc)
end
def newname
#review = Review.find(params[:id])
if #review.update_attribute(:title, sanitize(params[:title]))
format.json { render json: { status: 200 } }
else
format.json { render json: { status: 500 } }
end
end
end
The biggest flaw is that update_attribute skips all the validations, hence, your else statement will rarely/never be executed. Change it to:
#review.name = sanitize(params[:title])
if #review.save
#...
and it should be much better.
To build upon BroiSatse's answer, I would definitely use save instead of update_attribute. I would also return the errors that occur so the user can parse or show them. If you're on Rails 4, use strong params (declare in a private method in controller)
Rails 3:
def newname
#review = Review.find(params[:id])
#review.title = sanitize(params[:title])
if #review.save
format.json { render json: { status: 200 } }
else
render :json => {:errors => #review.errors.full_messages}, :status => 422
end
end
Rails 4
class ReviewController < ApplicationController
before_action :set_review, only [:newname] #list additional methods as needed...
...
def newname
##review is retrieved from set_review
if #review.update(review_params)
format.json { render json: { status: 200 } }
else
render :json => {:errors => #review.errors.full_messages}, :status => 422
end
end
private
def set_review
#review = Review.find(params[:id])
end
def review_params
params.require(:review).permit(:title)
end
end
I think you could perhaps do something similar to:
class ReviewController < ApplicationController
def index
#reviews = Review.all.order(created_at: :desc)
end
def newname
#review = Review.find(params[:id])
if #review.update(:title => sanitize(params[:title]))
render json: #review
else
render :json => { errors: #review.errors.full_messages }, status: 422
end
end
end
The idea being to stay 'on the rails' and let the conventions do the work for you.
This addresses the
status code
method used to update
errors
I juts start with the developing of an API using RAILS. Im doing a simple example of my own but I have an error when I want to see the result in my API.
Controller:
class EnergyCalcController < ApplicationController
def index
file_path = Rails.root.join('db','test_file.js')
file_gen = File.read(file_path)
#data_hash_gen = JSON.parse(file_gen)
end
end
In controllers/api/energy_calc_controller.rb
class Api::EnergyCalcController < ApplicationController
def index
render json: #data_hash_gen
end
end
Routes
Rails.application.routes.draw do
namespace :api do
resources :energy_calc
end
get 'energy_calc/index'
Views/energy_calc/index.html.erb
<h1>EnergyCalc#index</h1>
<p>Find me in app/views/energy_calc/index.html.erb</p>
<%= #data_hash_gen %>
In the view is printing me the data normally. But when I tried to access: http://localhost:3000/api/energy_calc.json I got null
Any idea?
Put your EnergyCalcController index methods code in to Api::EnergyCalcController's index method. Like this,
class Api::EnergyCalcController < ApplicationController
def index
file_path = Rails.root.join('db','test_file.js')
file_gen = File.read(file_path)
#data_hash_gen = JSON.parse(file_gen)
render json: #data_hash_gen
end
end
You don't need to have two different controllers for rendering different formats.It is redundant.You could render HTML and JSON both in a single action.
class EnergyCalcController < ApplicationController
def index
file_path = Rails.root.join('db','test_file.js')
file_gen = File.read(file_path)
#data_hash_gen = JSON.parse(file_gen)
respond_to do |format|
format.json {
render :json => #data_hash_gen
}
format.html {
#Objects exclusively needed to render html
}
end
end
end
I'm using Rails 4.0.2 with paperclip for image upload in my project. Also I need to send a full image path of paperclip. So I can do it with add new field and set image path manually in my show controller method for particular record.
show
def show
respond_to do |format|
format.html
format.json { :json => JSON::parse(#demo.to_json.merge("new_field" => #demo.image_url.url).to_json}
end
end
When I view Json for any of my record, this is will showing good.
{
id: "1",
name: "demo",
new_field: "/demo/1/original/file.jpg"
}
In same scenario, I need to get the full image path of paperclip image for all records when I am requesting to index method on controller
index
def index
#demos = Demo.all
respond_to do |format|
format.html
format.json { :json => Demo.all.to_json}
end
end
I tried some of codes, but I don't know how exactly to write
def index
#demos = Demo.all
#demos.each do |demo|
new_field = {"new_field" => #demo.image_url.url}
# After I stucked with logic, how to uppend with 'demo'.
end
respond_to do |format|
format.html
format.json { :json => Demo.all.to_json}
end
end
How do I iterate my individual Demo model and How to merge full image path into each record.
I found the solution for my question,
def index
#demos = Demo.all
#demos_data = []
#demos.each do |demo|
new_field = {"new_field" => #demo.new_field.url}
demo = JSON::parse(demo.to_json).merge(new_field)
#demos_data << demo
end
respond_to do |format|
format.html
format.json { :json => #demos_data}
end
end
I suggest you to use two approaches, 1)use active model serializer to expose json response. 2) use jbuilder library to expose custom fields. Still you need help please let me know.
Try this:-
def index
#demos = Demo.all
#demos_data = []
#demos.each do |demo|
demo["new_field"] = #demo.image_url.url
#demos_data << demo
end
respond_to do |format|
format.html
format.json { :json => #demos_data}
end
end
maybe you can try:
def index
#demos = Demo.all
#demos.map do |demo|
new_field = {"new_field" => #demo.image_url.url}
demo.attributes.merge(new_field)
end
respond_to do |format|
format.html
format.json { :json => #demos}
end
end
attributes method returns a hash of all the object attributes, just need merge new key-value into the returned hash.
Another way of doing it is in your controller where you are rendering the json
render json: #merchants,
include: {
offers: {
except: [:created_at, :updated_at],
include: {
categories: {
except: [:created_at, :updated_at]
}
}
},
location: {
methods: :country_name,
except: [:created_at, :updated_at]
}
},
except: [:created_at, :updated_at]
Note the methods: :country_name, there you can render methods from your model as json attributes. and through include: ... you can eager load and render related models.
I want to override Kaminari's pagination when rendering JSON, or tell it to return all with pagination.
In App1, I am using ActiveResource to access App2's Group model:
class Group < ActiveResource::Base
self.site = "http://www.app2.com:3000"
end
Here's App2's Group model:
class Group < ActiveRecord::Base
default_scope order('name asc')
paginates_per 10
This is my controller. The Group.search stuff is ransack:
class GroupsController < ApplicationController
# GET /groups
# GET /groups.json
def index
#search = Group.search(params[:q])
#groups = #search.result.page params[:page]
respond_to do |format|
format.html # index.html.erb
format.json { render json: #groups }
end
end
I've added eleven groups to App2. In the console of App1 I get:
[45] pry(main)> Group.all.count
=> 10
What is the best way to do this without changing the HTML pagination rendering?
You can prepare all the common logic you need but only apply pagination for the HTML format:
def index
#search = Group.search(params[:q])
#groups = #search.result
respond_to do |format|
format.html { #groups = #groups.page(params[:page]) }
format.json { render :json => #groups }
end
end
You can run different code in different formats:
def index
respond_to do |format|
format.html {
#search = Group.search(params[:q])
#groups = #search.result.page params[:page]
} # index.html.erb
format.json {
render json: Group.all
}
end
end