Rails scaffold
generated the following:
respond_to do |format|
if @student.save
format.html { redirect_to @student, notice => 'Student was successfully created.' }
format.json { render :show, status: :created, location: @student }
else
format.html { render :new }
format.json { render json: @student.errors, status: :unprocessable_entity }
end
end
After reading this I understand how the respond_to
is working (sort of), but I don't get what format
is doing. Shouldn't it be either format.html
or format.json
and not both? What are these two lines actually doing?
format.html { render :new }
format.json { render json: @student.errors, status: :unprocessable_entity }
Is there an implied if
in there? Is it something like
if (format == html) {}
if (format == json) {}
Side note: Why does update
require the respond_to
block while show
will handle /students/1.json
or /students/1
without any logic at all?
format
is a local variable that respond_to
yields. When you do format.html {}
you are actually registering a callback block for a format.
Rails goes through the registered formats and tries to find a compatible format to the MIME type in the request. If there is no handler it will raise an error.
This could be explained as something like using syntactic sugar on top of a case
statement (the Ruby equivalent of a switch statement). But the analogy is not completely accurate since Rails does a bit of work in matching the request type.
Also the code inside your block is not executed when the format.html
block is registered (as it would be if it was just a conditional statement) but rather when respond_to
finishes or not at all if you are using for example E-Tag caching.
Why does update require the respond_to block while show will handle /students/1.json or /students/1 without any logic at all?
Rails handles many actions by using a convention over configuration approach and guessing the intent of the action.
This what it would look like if you type it out:
def PostsController < ApplicationController
def index
# rails auto-magically fills in the controller with something
# like this
@posts = Post.all
respond_to do |format|
format.html { render :index }
format.json { render json: @posts }
end
end
def show
# convention over configuration is awesome!
@post = Post.find(params[:id])
respond_to do |format|
format.html { render :show }
format.json { render json: @post }
end
end
def new
@post = Post.new
render :new
end
def edit
@post = Post.find(params[:id])
render :edit
end
end
Rails assumes that there is a resource with the same name as the controller and auto-magically fills in the controller action. It also assumes there is a view in app/views/posts/(:action).html.[erb|haml|slim|jbuilder]
. This is known as implicit rendering.
The comments show roughly what action rails attempts.
It does not fill in actions which operate on data (create, update, destroy) since the actual implementation can vary greatly and it's hard to make useful guesses.