What's the use case of 'respond_to' in rails? - ruby-on-rails

respond_to do |format|
format.html
format.xml { render :xml => #mah_blogz }
end
respond_to do |format|
format.js
end
What's this respond_to, format.html, format.xml and format.js? What's their purpose and how do they work?

Here's the link to the documentation
http://api.rubyonrails.org/classes/ActionController/MimeResponds/ClassMethods.html#method-i-respond_to
Its a way of responding to the client based on what they are asking for, if the client asks for HTML, Rails will send back HTML to the client, if they ask for XML then XML.

Say you are doing this:
class UsersController < ApplicationController
def create
#
#your code
#
respond_to do |format|
format.xml {render :xml => xxx}
format.json {render :json => xxx}
format.html {render xxx}
end
end
def edit
#
#your code
#
respond_to do |format|
format.xml {render :xml => xxx}
format.json {render :json => xxx}
format.html {render xxx}
end
end
end
rather do:
class UsersController < ApplicationController
respond_to :xml, :json, :html
def create
#
#your code
#
respond_with xxx
end
def edit
#
#your code
#
respond_with xxx
end
end
and thats how you keep the code DRY (Dont Repeat Yourself)

Related

`respond_to` without block argument

Presently I'm using respond_to like this.
respond_to do |format|
format.html {render layout: false }
end
I know a sentence like respond_to {| format | format.html } can be written respond_to :html.
But how can I write without first block if format.html also have a block argument?
I want to write like respond_to :html, {render layout: false }.
Could it be you have this confused with respond_with?
class PeopleController < ApplicationController
respond_to :html
def index
#people = Person.all
respond_with #people
end
end
respond_with can be configured just as respond_to:
respond_with(#people) do |format|
format.html { render layout: false }
end
See the API documentation or this Railscast for more information about respond_with.

Rails Routes.rb

How does rails know how to map to each function in the controller if the routes.rb file only specifies:
resources :users
but inside the UsersController you have
class UsersController < ApplicationController
# GET /users
# GET /users.json
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #users }
end
end
# GET /users/1
# GET /users/1.json
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render :json => #user }
end
end
# GET /users/new
# GET /users/new.json
def new
#user = User.new
respond_to do |format|
format.html # new.html.erb
format.json { render :json => #user }
end
end
# GET /users/1/edit
def edit
#user = User.find(params[:id])
end
# POST /users
# POST /users.json
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to #user, :notice => 'User was successfully created.' }
format.json { render :json => #user, :status => :created, :location => #user }
else
format.html { render :action => "new" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
end
# PUT /users/1
# PUT /users/1.json
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to #user, :notice => 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render :action => "edit" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
end
How does rails determine that for instance the index function maps to GET/users while the create function maps to POST/users?
How does resources :users even know to map to the UsersController?
Rails is based around the 'convention over configuration' paradigm.
As such, the "resources :users" line indicates that all the standard CRUD methods are supported by the corresponding UsersController <-- the 'Users' prefix matches to the Controller, Model etc.
Please check the rails routes guide: http://guides.rubyonrails.org/routing.html
And to see in practice what the routes declaration does issue this command in your project directory:
rake routes
Also as mentioned before, stick with conventions and remember that rails is a very opinionated piece of software.

Unable to create a REST API for my RoR app

I am trying to create a REST API for my app.
The map.connect_resource :book causes the following error, when executing rake test:functionals:
Error: undefined local variable or method `map' for #
<ActionDispatch::Routing::Mapper:0x8a11e74>.
In my app, I'm trying to implement RoR with MySQL with the following table data.
Table Name: Object
Fields: object_id, Object_name, Object_description etc...
I would like to create a REST API object for querying the above database and retrieving the data. What's the best way to proceed?
That is a reallyyyyyyy old tutorial (from 6 years ago!!!). I would recommend reading this guide instead: http://guides.rubyonrails.org/routing.html
Assuming you are running Rails 3, you should just put this in your routes.rb file:
resources :books
That will expose routes for your BooksController so you can access:
HTTP Verb Path action used for
-----------------------------------------------------------------------
GET /books index display a list of all books
GET /books/new new return an HTML form for creating a new book
POST /books create create a new book
GET /books/:id show display a specific book
GET /books/:id/edit edit return an HTML form for editing a book
PUT /books/:id update update a specific book
DELETE /books/:id destroy delete a specific book
So in your BooksController you would then have:
class BooksController < ApplicationController
# GET /books
# GET /books.xml
def index
#books = Book.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #books }
end
end
# GET /books/1
# GET /books/1.xml
def show
#book = Book.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #book }
end
end
# GET /books/new
# GET /books/new.xml
def new
#book = Book.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #book }
end
end
# GET /books/1/edit
def edit
#book = Book.find(params[:id])
end
# POST /books
# POST /books.xml
def create
#book = Book.new(params[:book])
respond_to do |format|
if #book.save
format.html { redirect_to(#book, :notice => 'Book was successfully created.') }
format.xml { render :xml => #book, :status => :created, :location => #book }
else
format.html { render :action => "new" }
format.xml { render :xml => #book.errors, :status => :unprocessable_entity }
end
end
end
# PUT /books/1
# PUT /books/1.xml
def update
#book = Book.find(params[:id])
respond_to do |format|
if #book.update_attributes(params[:book])
format.html { redirect_to(#book, :notice => 'Book was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #book.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /books/1
# DELETE /books/1.xml
def destroy
#book = Book.find(params[:id])
#book.destroy
respond_to do |format|
format.html { redirect_to(books_url) }
format.xml { head :ok }
end
end
end

How to convert this respond_to options to use Rails 3 version?

respond_to do |format|
if #user.save
format.js { render :nothing => true, :status => :ok, :location => #user }
else
format.js { render :json => #user.errors, :status => :unprocessable_entity }
end
end
All options I've tried (like putting respond_to :js at the top of controller, etc) don't quite work the way as in this.
Rails 3 Format:
Use respond_to :json and respond_with(#user)
respond_to :json # You can also add , :html, :xml etc.
def create
#user= User.new(params[:user])
#---For html flash
#if #user.save
# flash[:notice] = "Successfully created user."
#end
respond_with(#user)
end
# Also, add :remote => :true, :format => :json to the form.
Try using format.json instead of format.js in your controller and :remote => :true, :format => :json in corresponding form.
Though, I'm not quite sure whether format.json or format.js should be used in that case. As default scaffolding from Rails 3 generates controllers with format.json and you're doing render :json in response I believe format.json is the right way to go. And format.js should be used when you return a piece of JS that should be executed.
The URL your are requesting should end with .json like this: /controller/action.json
If that is not possible:
You should set the 'accepts' parameter to 'application/json' while sending the ajax request.
Search for how to use 'accepts' here: http://api.jquery.com/jQuery.ajax/
And in the server side:
format.json { render :json => #user.errors, :status => :unprocessable_entity }

RoR - Two respond_to formats using same block?

Is there something like:
respond_to do |format|
format.html || format.xml do
#big chunk of code
end
end
I would like to do that for DRY's sake.
Respond_to actually allows you to specify your common block for different formats by using any:
format.any(:js, :json) { #your_block }
You can use a format like this:
class PeopleController < ApplicationController
respond_to :html, :xml, :js
def index
#people = Person.find(:all)
respond_with(#people) do |format|
format.html
format.xml
format.js { #people.custom_code_here }
end
end
end
Which would achieve what you are looking for, if you have a situation that is more complex let me know. See this article on the respond_with method for more help.
when you
respond_to do |format|
format.html do
#block
end
format.xml do
#block
end
end
or you
respond_to do |format|
format.html { #block }
format.xml { #block }
end
you are taking advantage of ruby blocks, which are evaluated as Procs. Therefore you could do
respond_to do |format|
bcoc = Proc.new do
# your big chunk of code here
end
format.html bcoc
format.xml bcoc
end
but perhaps you could move some of that logic into your data structure?

Resources