can I use rabl without using .json in the url? - ruby-on-rails

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

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

Ruby on Rails: setting content-type in `responds_to { |f| f.any`

Using Rails API I had a /events endpoint that could be called without specifying the format; no /events.json needed. The route:
resources :events, defaults: { format: :json }
The controller:
def index
#events = get_events
render json: #events
end
Now I want to respond to /events.csv with a CSV file, but otherwise keep the behavior unchanged. Before getting to the CSV, I add a respond_to block:
def index
#events = get_events
respond_to do |format|
format.any { render json: #events }
end
end
This has almost the same behavior as the previous approach, except that requests to /events now have a header Content-Type: application/html rather than application/json.
I find this surprising, given that I specify json in that block! But looking at the Rails source code, I see that they indeed skip setting the Content-Type header for any responses. This makes it always set Content-Type to whatever the user requested, rather than matching Content-Type to the actual response. If someone requests XML, it returns JSON but calls it XML. If someone requests HTML, as I am in my tests without format: :json and when I test without the .json in my browser, it returns JSON but calls it HTML.
Why? And how to I override this and force the Content-Type/mime type to match the actual response?
Rails 6
This issue seems to be changed in Rails 6 so that format.any { render json: #events } will return the Content-Type as application/json as expected
Rails 5
For Rails 5 a workaround can be to force change the Content-Type header:
def index
#events = get_events
respond_to do |format|
format.any {
response.headers['Content-Type'] = 'application/json; charset=utf-8'
render json: #events
}
end
end

Render different controller methods as JSON in Rails 5.2

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

Rails 3 route with json format not working

I have a route that I need to call like so:
/images/get_subcollections.json?id=1234
I have this in my routes file:
resources :images do
collection do
get 'get_subcollections'
end
end
I have this in my controller:
def get_subcollections
collection = Collection.find(params[:id])
respond_to do |format|
format.json { render :layout => false, :json => collection.to_json(:methods=>:get_subcollections) }
end
end
The app just sits there when I call the URL. The request doesn't get logged or anything. Any ideas? Thanks!
Have you inspected the response using firebug or chrome's dev tools? Is it just that layout: false is stopping you seeing anything?

Preventing direct URL access to Rails Controller Methods

I have a particular Rails controller method that returns some JSON when I do an javascript ajax request in the front-end.
However, I want to prevent users from directly typing in the url, which displays the JSON that the method returns. I also want to still be able to perform my ajax requests. How can I go about doing this simply? Thanks!!
Just a thought... You could do something custom in your respond_to block for html requests.
respond_to do |format|
format.html { ... } # give them a 404 response?
format.js { render :json => #obj }
end
Or maybe your html.erb template with that name could just show some kind of access denied message. Then you'd just have this:
respond_to do |format|
format.html
format.js { render :json => #obj }
end
You could wrap your action with
if request.xhr?
...
end
The respond_to filter in rails3 controllers is pretty sweet.
YourJsonController < ApplicationController
respond_to :json
def index
#non-json requests will receive a 406 error
end
end
In your routes.rb, you can add :via => :post so your URL accepts only POST requests. See "HTTP Verb Constraints" at http://guides.rubyonrails.org/routing.html

Resources