Some developers think of redirect_to as some kind of goto command, moving execution from one place to another in your Rails code. This is not true. Your code stops working and is waiting for a new request for the browser. It just happens that you told the browser what request it should do next by sending an HTTP 302 status code.
Consider these steps to see the difference:
def index @books = Book.all end def show @book = Book.find_by(id: params[:id]) if @book.nil? render action: "index" end end
There will probably be a problem with the code in this form if the @book variable is nil. Remember that render :action does not run any code in the target action, so nothing will set up the @books variable, which is likely to require an index. One way to fix this is to redirect instead of rendering:
def index @books = Book.all end def show @book = Book.find_by(id: params[:id]) if @book.nil? redirect_to action: :index end end
Using this code, the browser will make a new request for the index page, the code in the index method will be launched, and everything will be fine.
The only drawback of this code is that the browser requires a two-way trip: the browser requested a show action with / books / 1 and the controller detected that there are no books, so the controller sends a redirect response 302 to the browser telling it to go to / books /, the browser agrees and sends a new request back to the controller, now requesting the index action, the controller then receives all the books in the database and displays the index template, sends it back to the browser, which then displays it on the screen.
Although this added delay may not be a problem in a small application, you need to think about whether response time is a problem. We can demonstrate one way to deal with this contrived example:
def index @books = Book.all end def show @book = Book.find_by(id: params[:id]) if @book.nil? @books = Book.all flash.now[:alert] = "Your book was not found" render "index" end end
This will reveal that there are no books with the specified ID, fill the @books instance variable with all the books in the model, and then directly render the index.html.erb template, returning it to the browser with a flash to tell the user what happened.