Render different controller methods as JSON in Rails 5.2 - ruby-on-rails

I have a resource that renders as JSON perfectly fine at localhost:3000/gins.json from #gins = Gin.order(name: :desc).
Which will return ALL gins. However, I'd like to have a JSON response that only returns the last 4 gins, to use elsewhere. In the controller I also have:
#latestgins = Gin.order("created_at DESC").first(4)
The above would work in an index.html.erb view with <%= #latestgins.name %>, but how do I get the JSON for this? I have tried render json: #latestgins but navigating to localhost:3000/latestings.json, of course, gives a routing error.
I suspect I'm attacking this in completely the wrong way, but only just starting out with Rails API.

you can add respond to format json in your index method:
def index
#gins = Gin.order(name: :desc)
#latestgins = Gin.order("created_at DESC").first(4)
respond_to do |format|
format.html
format.json { render json: #latestgins }
end
end
your #latestgins is now available here : localhost:3000/gins.json
Edit
If you want a custom route to display your data, just add it in your routes:
defaults format: :json do
get 'last4gins', to: "gins#index"
end
Your data for the last 4 entries is available at http://localhost:3000/last4gins.json, at http://localhost:3000/last4gins but also at localhost:3000/gins.json
If you want to keep the gins index route clean, you can also create a custom method and remove the #latestgins from your index:
# routes
get 'last4gins', to: "gins#last4gins"
#controller
def index
#gins = Gin.order(name: :desc)
end
def last4gins
#latestgins = Gin.order("created_at DESC").first(4)
render json: #latestgins
end
Now the data is no more available at /gins.json

Related

Rails routes: json endpoint naming convention

I have an endpoint that renders json:
def controller_method
render json: json_response
end
However, I am curious about the naming convention of the route. The following naming leads to ActionController::UnknownFormat Controller#controller_method is missing a template for this request format and variant.:
get '/controller/controller_method.json', to: 'controller#controller_method'
However, I successfully get the json when the route is named:
get '/controller/controller_method_data', to: 'controller#controller_method'
Am I not allowed to put .json in the url routes? Any way that I can allow .json be the name of the route?
There is a much easier way to respond to different formats - just use ActionController::MimeResponds
get '/controller/controller_method', to: 'controller#controller_method'
class Controller < ApplicationController
def controller_method
respond_to do |format|
format.json { render json: { hello: 'world' } }
format.html # renders the view implicitly
format.txt { render plain: 'Hello world'}
end
end
end

can I use rabl without using .json in the url?

I have rabl up and running.
I have this in routes:
get 'biblios/collection/:biblio_urn' => 'biblios#biblio_rabl', as: 'collection_biblio'
in the controller:
def biblio_rabl
biblio = Biblio.where(biblio_urn: params[:biblio_urn]).take
end
This url points to the correct result :
http://localhost:3000/dts/biblios/collection/urn:cts:froLit:ed_desmarez:1900
I would like that url to always respond using rabl and showing the the template dts/biblios/biblio_rabl.json.rabl
I mean without adding .json at the end of the url.
I have tried this in the routes.rb, but it doesn't redirect :
get 'biblios/collection/:biblio_urn' => 'biblios#biblio_rabl', as: 'collection_biblio', to: redirect('biblios/collection/%{biblio_urn}.json')
Is that possible at all?
You can force the response to be json by changing the request format in the controller:
request.format = :json
Then make sure you have a respond_to block like this because it's always better to be explicit about your responses:
def biblio_rabl
respond_to do |format|
format.json { json: Biblio.where(biblio_urn: params[:biblio_urn]).take }
end
end

Rails Routes with Param - Controller ignoring param

I'm trying to figure out how to do filters for a datatable, so my thought in the interim is to have the an <option> apply a param to the URL, and the basis of the table to change, however, my Controller seems to be ignoring the parameters
def index
#steam_games = SteamGame.all
#steam_games = SteamGame.where("#{params[:genre]} = ANY (genres)") if params[:genre].present?
respond_to do |format|
format.html
format.json { render json: SteamGamesDatatable.new(view_context, #steam_games) }
end
end
Is the best way I can think to apply it.
To test I also added in
get '/steam_games/:genre', to: 'steam_games_controller#index' to the Routes, even though I'd like the URL to not change.
My debugger is showing
--- !ruby/object:ActionController::Parameters
parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
genre: indie
controller: steam_games
action: index
permitted: false
ON load I see Parameters: {"genre"=>"indie"} in the console.
Why is it that this isn't working? To note the genres is an ARRAY which is why I have the where as such, but that shouldn't change the parameter binding.
(Unsure what else to link reg. this).
It's POSSIBLE Datatables is trumping the index of the Controller, but I don't believe so since I feed it the list.
It seems to me that this is a strong params issue. You need to permit the params be used. You can try something like this in your controller.
def index
#steam_games = SteamGame.all
#steam_games = SteamGame.where("#{steam_game_params[:genre]} = ANY (genres)") if steam_game_params[:genre].present?
respond_to do |format|
format.html
format.json { render json: SteamGamesDatatable.new(view_context, #steam_games) }
end
end
private
def steam_game_params
params.permit(:genre)
end
Here's a link to ActionController::Parameters documentation.

Restful api with rails

I am learning how to write a restful API using RoR and have a question related to it. So, I will explain what I did along with the code.
This is how my controller looks like:
class EmployeesController < ApplicationController
require 'rest_client'
def index
uri = "localhost:3000/employees"
rest_resource = RestClient::Resource.new(uri)
users = rest_resource.get # will get back you all the detail in json format, but it will we wraped as string, so we will parse it in the next step.
#users = JSON.parse(users, :symbolize_names => true) # convert the return data into array
#users.each do |u|
logger.info(u.id)
end
# return based on the format type
respond_to do |format|
format.json {render json: #users}
format.xml {render xml: #users}
format.html
end
end
end
In my Gemfile, I have included rest-client as well.
gem 'rest-client'
My routes are :
root 'employees#index'
resources 'employees'
Hope everything is fine till now.
Now, when I send:
-> Curl request to 'http://localhost:3000/employees', it gets stuck.
-> Get request(by typing in the browser) to 'http://localhost:3000/', it get stuck here as well.
What is that which I am missing?
You don't need RestClient as you're writing a server here, not a client. The browser acts as the client. Remove the call to localhost as it's creating a loop.
The URL for this should already be set in your routes.rb, maybe using:
resources :users
Assuming this is a typical app, the show function should be reading from the database using ActiveRecord.
class EmployeesController < ApplicationController
def index
#users = User.all
respond_to do |format|
format.json {render json: #users}
format.xml {render xml: #users}
format.html
end
end
end
Do you have some other application running on localhost:3000? Because if not, then what your server does is calling himself again and again, causing a loop.
If you do have some other application, which fetches users from database, then be sure its running on some other port, other than this your rails app.
If you have only 1 app, then you don't need rest client.
You actually can do this without any additional gem. You just need to declare your routes according to what you want to expose to your API users and return the type (xml, json, ...) accordingly.

Rails 4 *.json.jbuilder files ignored

In my Rails 4.1.1 app (which has the jbuilder gem included), json views always output all columns in the table, ignoring the app/views/[model]/*.json.jbuilder files.
In routes.rb, I have:
resources :workshops do
resources :memberships
resources :events
end
In events_controller.rb, I have:
# GET /workshop/:workshop_id/events
# GET /workshop/:workshop_id/events.json
def index
#events = #workshop.events
respond_to do |format|
format.html
format.json { render json: #events }
end
end
I set the #workshop variable in a "before_action" in the controller.
When I visit /workshops/f00/events, it displays in HTML format as expected.
If I make the file, app/views/events/index.json.jbuilder:
json.events do
end
...when I visit /workshops/f00/events.json, I expect that the output would be empty. However, I get the contents of the entire #events in JSON format.
What I would like to see is only particular fields being output, given a app/views/events/index.json.jbuilder that contains:
json.array!(#events) do |event|
json.extract! event, :id, :title, :description
json.start event.starts_at
json.end event.ends_at
json.url workshop_event_url([#workshop, event], format: :json)
end
... but no matter the contents of the .jbuilder file, the output is always the same. Could anyone tell me why my .jbuilder file is being ignored, and how to get it working?
The line format.json { render json: #events } will always render the #events array since the url /workshops/f00/events accepts both html and json formats and you're rendering #events when hitting the url with the json format.
If you want to render the data in app/views/events/index.json.jbuilder change:
respond_to do |format|
format.html
format.json { render json: #events }
end
to:
respond_to do |format|
format.html
format.json
end
By not rendering the #events array you rely on Rails to output whatever is in app/views/events/index.json.jbuilder.

Resources