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

in cn •  7 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學習推薦書籍

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

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