這篇筆記會聚焦render在controller中的常見用法。
預設render同名的view
在Rails中contoller中會預設去render與路由同名的view。舉例來說,當你在PagesController的index action中,即便你不指定render的view,Rails也會自動幫你找尋模板
class PagesController < ApplicationController
def index
@pages = Page.all
# render :new
# 即使沒有render,Rails也會自動幫你抓取app/views/pages/index.html.erb的模板
end
end
render同一個controller下的template
以下的程式碼代表的是,當update不成功時,render同一個controller下的edit template
class PagesController < ApplicationController
def update
@page = Page.find(params[:id])
if @page.update(page_params)
redirect_to page_path(@page)
else
render :edit
# 用途跟render temlate: :edit一樣
end
end
end
render其他contoller的view
如果想要
像是categories controller下的index template的話,可以這樣做
class PagesController < ApplicationController
def index
@pages = Page.all
render "categories/index"
# 路徑會是相對於app/view
end
end
render使用inline選項
我們可以使用inline的選項,讓我們不使用view的模板,而是使用提供的一段erb程式碼
# app/controllers/pages_controller.rb
def index
pages = Page.all
render inline: "<% pages.each do |p| %><p><%= p.user %></p><% end %>"
end
頁面產生,
雖然透過inline選項,可以將erb程式碼放在controller中render,但是實務上很少這麼做。
因為這種做法等於是在controller中混用了view,跟Rails的MVC原則相衝突,基本上還是會把要render的內容拉到模板中。
render純文字(plain)
如果只想要render純文字,可以透過plain選項
# app/controllers/pages_controller.rb
def index
pages = Page.all
render plain: "安安,我是純文字"
end
可以得到
當我們使用plain時,連預設的版型(layout)都不會使用。如果需要使用layout的話,記得加上layout: true
# app/controllers/pages_controller.rb
def index
pages = Page.all
render plain: "安安,我是純文字", layout: true
end
render json
如果要render json的話,可以使用json option,並將想要傳遞的object透過實體變數傳入。
# app/controllers/pages_controller.rb
def index
@pages = Page.all
render json: @pages
end
這樣會得到
這邊值得注意的是不需要對要render的object呼叫 to_json。因為:json選項會試射自動對object呼叫 to_json方法。
render和redirect_to的不同
render告訴Rails要用那個View或是其他 Asset)。而redirect_to則是告訴瀏覽器對不同的URL發一個新請求。舉例來說,可以在程式碼任何一個地方做轉址,比如轉到 photos的index就會是
redirect_to photos_path
不過需要注意的是
一個action中只能有一個render或redirect_to,不然你會得到一個DoubleRenderError例外錯誤。
避免render多次
在上一段我們有提到,一個action中只能有一個redirect_to或render。如果你在同一個controller中render多次的話,
def show
@book = Book.find(params[:id])
if @book.special?
render action: "special_show"
end
render action: "regular_show"
end
你可能會得到以下的錯誤訊息
上面那段程式碼會出錯的原因是,當@book.special?為true時,會先render special_show
接著再去render regular_show
。當一個controller render多次時就會出現錯誤。
解決方法就是讓action只出現一次render或action。如果真的要使用多次,那要加上and return
來離開目前的action。
使用and return
多個render
def show
@book = Book.find(params[:id])
if @book.special?
render action: "special_show" and return
end
render action: "regular_show"
end
redirect_to和render同時存在
def show
@book = Book.find(params[:id])
if @book.special?
redirect_to root_path
end
render action: "regular_show"
end
各種同樣效果的render寫法
以下幾種寫法均能render app/views/books/edit.html.erb這個template。
render :edit
render action: :edit
render "edit"
render "edit.html.erb"
render action: "edit"
render action: "edit.html.erb"
render "books/edit"
render "books/edit.html.erb"
render template: "books/edit"
render template: "books/edit.html.erb"
render "/path/to/rails/app/views/books/edit"
render "/path/to/rails/app/views/books/edit.html.erb"
render file: "/path/to/rails/app/views/books/edit"
render file: "/path/to/rails/app/views/books/edit.html.erb"
參考資料
Rails 算繪與版型
Layout, Render 與 View Helper
Bro if you make in english. will help alot more people.
Thanks