Rails' respond_to - syntax analysis - ruby-on-rails

Here is a Rails code:
respond_to do |format|
format.html
format.xml { render :xml => #users }
format.json { render :json => #users }
end
I know what it does. But I don't know the meaning of the commands syntax-wise.
format.xml -- what is xml, is this a method which an object format has, correct? Where do I find its signature (or description)?
{ } -- a block or a hash? I think this is a block.
render -- a method? where do I find its signature (where in api docs)?
:xml => #users -- a hash, where :xml => is a key, correct?
So it could be reprented as, right?:
respond_to do |format|
format.html
format.xml do
render(:xml => #users)
end
format.json do
render(:json => #users)
end
end

format.*
Using the debugger, I learnt that format is an instance of ActionController::MimeResponds::Collector. It includes AbstractController::Collector, which uses method_missing to respond to various format calls.
if Mime::SET.include?(mime_constant)
AbstractController::Collector.generate_method_for_mime(mime_constant)
send(symbol, &block)
else
# ...
{ render xml: ... }
Looking at method_missing, it's clear that it expects a block.
render
Yes, render is a method. Documentation.
:xml => #user
Yes, it's a hash. The key is the symbol :xml. It can also be written as
render xml: #user
render(xml: #user)
render({xml: #user})
render({:xml => #user})

format comes from the request made to the method, http://app.com/controller/method.format where format could be .html or .csv etc. The meaning of format.xml is simply to check if the user requested an xml page (http://app.com/controller/method.xml.
Block, just like you describe.
At the apidock! http://apidock.com/rails/ActionController/Base/render
Correct, render will act depending on the key that exists. In your case, as the existing key is :xml the render method will output #users formatted as XML.

Related

dynamic rendering based on data results

I am curious if this is even possible. I am looking to render data based on the results of an action in ruby on rails. Here is the code:
def convert
render :text => Item.convert(params[:file], params[:output])
end
As you can see currently it just renders text. The item model takes in two parameters: a file and output. The output could be xml, json, plain text, etc. Some type of data. What I was hoping I could do is that I could render the output based on the output parameter. But make it dynamic. I was hoping I could do:
def convert
#items = Item.convert(params[:file], params[:output])
respond_to do |format|
format.json { render :json => #items }
format.xml { render :xml => #items }
end
end
Something that would call the method and based on the data returned it would render the appropriate data. Testing the above code returns an empty page. The body tag is completely empty.
Any ideas?
thanks
Mike Riley
If you are relying on the name of params[:output] to determine what to render, I would write is as below:
def convert
#items = Item.convert(params[:file], params[:output])
if File.extname(params[:output].match("text"))
render :text => Item.convert(params[:file], params[:output])
elsif File.extname(params[:output].match("json"))
render :json => Item.convert(params[:file], params[:output])
elsif File.extname(params[:output].match("xml"))
render :xml => Item.convert(params[:file], params[:output])
else
render :html => "default_html"
end
end
and you should have a default_html.html.erb that you would render if the extension name of the file does not match what is expected

rails respond_to format.js API

I am an experienced JAVA and C++ developer and I am trying to understand how rails works.
I got this code below:
respond_to do |format|
if #line_item.save
format.html { redirect_to store_url }
format.js { render :json => #line_item, :mime_type => Mime::Type.lookup('application/json'),
:callback => 'javascriptFunction' }
and I've been searching the api that defines what I can pass inside the format.js {} but I could not find..
first of all: what kind of statement is format.js, is that a variable?
and most important: what attributes can I pass into format.js {} ? can you pass the direct link? I've searched over the http://api.rubyonrails.org/
respond_to do |format|
format.js # actually means: if the client ask for js -> return file.js
end
js here specifies a mime-type that the controller method would send back as a response;
Default Rails mime-types.
If you try also with format.yaml:
respond_to do |format|
format.js
format.yaml
end
that will mean that your controller will return yml or js depending on what the client-side is asking;
{} in terms of ruby is a block;
If you don't specify any rails will try to render a default file from app/views/[contoller name]/[controller method name].[html/js/...]
# app/controllers/some_controller.rb
def hello
respond_to do |format|
format.js
end
end
will look for /app/views/some/hello.js.erb; // at least in Rails v. 2.3.
If you do specify block:
respond_to do |format|
# that will mean to send a javascript code to client-side;
format.js { render
# raw javascript to be executed on client-side
"alert('Hello Rails');",
# send HTTP response code on header
:status => 404, # page not found
# load /app/views/your-controller/different_action.js.erb
:action => "different_action",
# send json file with #line_item variable as json
:json => #line_item,
:file => filename,
:text => "OK",
# the :location option to set the HTTP Location header
:location => path_to_controller_method_url(argument)
}
end
I believe this was the url you were looking for:
https://apidock.com/rails/ActionController/MimeResponds/InstanceMethods/respond_to
This might also be helpful to some, to see that you can actually render js directly within the format.js method, if you for example only have a small one line js statement you want to return, and you don't want to defer to a RJS file like controller_action_name.js.erb:
respond_to do |format|
format.html { redirect_to new_admin_session_path }
format.js { render :js => "window.location='#{ new_admin_session_path }'" }
end

Multiple JSON responses in a single Rails controller action

I have my show method on a controller in my application and in the response block I have
respond_to do |format|
format.html { render :layout =>'placing', :next_days => #next_days}# show.html.erb
format.xml { render :xml => #artist }
format.json { render :partial => "places/show.json", :artist => #artist } }
end
This, generates a json output based in the show.json partial in /places/1.json for example, but what if I want one more json output, like /places/alternative_1.json? How can I do that if there is already a json format block inside respond_to?
Any help is appreciated!
Cheers!
Then you will have to make some logic inside your format.json block changing what you are associating to :partial (currently is "places/show.json"), or create another route...
As format.json { render ... } is normal Ruby code, you could do something like:
format.json do
json_partial = json_for_this_case #example
render :partial => json_partial, :locals => {:artist => #artist}
end

Can Ruby on Rails's respond_to return a line when the format is not supported?

A usual usage of respond_to is like
respond_to do |format|
format.html
format.xml { render :xml => #data }
end
can it be made so that when the format is not supported (such as json or csv not being supported above), instead of returning nothing, return a text line saying "the format is not supported", or better yet, have it automatically report "only html and xml is supported"? It can know only html and xml are supported by the existing format.html and format.xml lines there. (if possible)
You should be able to use format.all
respond_to do |format|
format.html
format.xml { render :xml => #data }
format.all { render :text=>'the format is not supported' }
end
If you want to list the supported formats you'll need to extend the Responder class.
Put this in something like config/initializers/extend_responder.rb
module ActionController
module MimeResponds
class Responder
def valid_formats
#order.map(&:to_sym)
end
end
end
end
Then use this in your controller:
respond_to do |format|
format.html
format.json { render :text=>'{}' }
format.all { render :text=>"only #{(format.valid_formats - [:all]).to_sentence} are supported" }
end

In Rails 3, respond_to and format.all works differently than Rails 2?

the code
respond_to do |format|
format.html
format.json { render :json => #switches }
format.xml { render :xml => #switches.to_xml }
format.all { render :text => "only HTML, XML, and JSON format are supported at the moment." }
end
the above will work in Rails 2.2.2. But in Rails 3, getting controller/index.html or index on the browser will both fall into the last line: "only HTML and JSON format are supported at the moment."
The only Rails doc I can find on this is
http://api.rubyonrails.org/classes/ActionController/MimeResponds/ClassMethods.html#method-i-respond_to
which current only states:
respond_to :html, :xml, :json
but they need separate templates for json and xml, and can't handle the "only HTML and JSON format are supported at the moment" case.
In rails3 you would write:
respond_with(#switches) do |format|
format.html
format.json { render :json => #switches }
format.xml { render :xml => #switches }
format.all { render :text => "only HTML, XML, and JSON format are supported at the moment." }
end
But this only works in correspondence with a respond_to block at the top of the file, detailing the expected formats. E.g.
respond_to :xml, :json, :html
Even in that case, if anybody for instance asks the js format, the any block is triggered.
You could also still use the respond_to alone, as follows:
#switches = ...
respond_to do |format|
format.html {render :text => 'This is html'}
format.xml {render :xml => #switches}
format.json {render :json => #switches}
format.all {render :text => "Only HTML, JSON and XML are currently supported"}
end
Hope this helps.
You may find it useful to watch this episode of railscasts, which illustrates the changes to controllers in Rails 3 and in particular the changes to the responder class (putting respond_to in the controller class itself and only using respond_with #object in the action):
http://railscasts.com/episodes/224-controllers-in-rails-3
The following works for me. I believe you have to specify the "render" part for html explicitly or it will use the format.any.
respond_to do |format|
format.html { render :html => #switches }
format.json { render :json => #switches }
format.xml { render :xml => #switches }
format.all { render :text => "we only have html, json, and xml" }
end

Resources