Sự khác biệt giữa render và redirect_to trong Rails
Với những người mới bắt đầu tìm hiểu về Ruby on Rails, phương thức render và redirect_to có thể dễ gây nhầm lẫn. Hai phương thức này đều xuất hiện ở cuối các action của controller, tạo HTTP response để trả về và sau cùng đều hiển thị view mới trên web browser. Bài viết sau đây sẽ chỉ ra sự khác ...
Với những người mới bắt đầu tìm hiểu về Ruby on Rails, phương thức render và redirect_to có thể dễ gây nhầm lẫn. Hai phương thức này đều xuất hiện ở cuối các action của controller, tạo HTTP response để trả về và sau cùng đều hiển thị view mới trên web browser. Bài viết sau đây sẽ chỉ ra sự khác nhau và khi nào nên dùng cho từng trường hợp.
render
Gọi tới render sẽ tạo một response đầy đủ trả về cho browser. Nếu không chỉ rõ render trong controller action, Rails sẽ tự động tìm kiếm và render template tương ứng dựa vào tên controller action.
#đoạn code dưới đây sẽ render app/views/foos/my_action.html.erb class FoosController < ApplicationController def my_action end end
Nếu bạn muốn render một view khác trong cùng controller, bạn có thể gọi render :action_name.
Hoặc render "another_controller/action" nếu bạn muốn render một view thuộc controller khác. Và thậm chí cả file ngoài Rails bằng cách chỉ rõ đường dẫn render "/users/another/apps/different_app/app/views/products/show".
Ngoài ra bạn cũng có thể render các định dạng khác như XML, JSON, Status Codes, Text, ...
#render một đoạn html ngắn render html: "<strong>Not Found</strong>".html_safe #render định dạng application/json (@product.to_json sẽ được gọi tự động) render json: @product #render định dạng application/xml (@product.to_xml sẽ được gọi tự động) render xml: @product #render định dạng text/javascript render js: "alert('Hello Rails');" #render status codes render status: 500 render status: :forbidden
redirect_to
Khác với render công việc của redirect_to là điều hướng browser, yêu cầu browser tạo một request mới đến một URL khác. Ví dụ: redirect_to photos_url. Hoặc tới một website khác redirect_to "https://google.com".
Mặc định Rails sử dụng "302 Moved" redirect, ta có thể thay đổi bằng option status redirect_to photos_path, status: 301.
Ngoài ra còn có phương thức redirect_back hoạt động tương tự nhưng là điều hướng về trang trước lúc thực hiện request (buộc phải chỉ định option fallback_location).
Chú ý: redirect_to và redirect_back không dừng method lại ngay mà chỉ thực hiện response, nghĩa là các câu lệnh sau đó trong method vẫn sẽ được thực thi.
Khi nào nên dùng?
Xét trường hợp sau
def index @books = Book.all end def show @book = Book.find_by(id: params[:id]) if @book.nil? render action: "index" end end
Khi biến @book là nil, bạn muốn render lại trang index nhưng render sẽ không chạy lại code của action index, vì thế biến @books sẽ không được khởi tạo và view sẽ không chính xác.
Điều bạn cần là browser thực hiện một request mới tới trang index, bằng cách sử dụng redirect_to action: :index thay thế.
Tuy nhiên, công việc lúc này lại trở nên dài dòng. Browser request một show action (books/1) và controller tìm kiếm với id được cung cấp nhưng không có kết quả, gửi lại 302 redirect response yêu cầu browser request đến index action. Browser lại tiếp tục tạo request mới, controller nhận request này, lấy dữ liệu từ database, render view và gửi trả lại cho browser. Trong trường hợp ứng dụng nhỏ thì việc thay thế trên lại không tối ưu hơn.
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
Vậy khi nào nên dùng render, khi nào nên dùng redirect_to tùy thuộc vào bạn. Hãy luôn đặt câu hỏi có nên tạo một request mới? khi phải quyết định.