[Rails]Rails中render常見的用法(1)

in #cn7 years ago

這篇筆記會聚焦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

Rails學習推薦書籍

Sort:  

Bro if you make in english. will help alot more people.
Thanks