edge
เพิ่มเติมที่ rubyonrails.org: เพิ่มเติมเกี่ยวกับ Ruby on Rails

ภาพรวมของ Action View

หลังจากอ่านเอกสารนี้คุณจะรู้:

1 Action View คืออะไร?

ใน Rails เราใช้ Action Controller และ Action View ในการจัดการคำขอเว็บ โดยทั่วไป Action Controller จะเกี่ยวข้องกับการสื่อสารกับฐานข้อมูลและการดำเนินการ CRUD ตามที่จำเป็น ในขณะที่ Action View จะรับผิดชอบในการรวบรวมการตอบสนอง

เทมเพลตของ Action View เขียนด้วย Ruby ที่ซ้อนอยู่ในแท็กที่ผสมผสานกับ HTML เพื่อหลีกเลี่ยงการรกตัวเทมเพลตด้วยรหัสที่ซ้ำซ้อน มีคลาสช่วยในการจัดการกับฟอร์ม วันที่ และสตริงที่ใช้บ่อย นอกจากนี้ยังสามารถเพิ่มคลาสช่วยใหม่ในแอปพลิเคชันของคุณได้อย่างง่ายดายเมื่อแอปพลิเคชันของคุณเติบโตขึ้น

หมายเหตุ: บางคุณสมบัติของ Action View เกี่ยวข้องกับ Active Record แต่นั่นไม่ได้หมายความว่า Action View ขึ้นอยู่กับ Active Record Action View เป็นแพคเกจที่อิสระที่สามารถใช้งานได้กับไลบรารี Ruby ใด ๆ

2 การใช้งาน Action View กับ Rails

สำหรับแต่ละคอนโทรลเลอร์ จะมีไดเรกทอรีที่เกี่ยวข้องในไดเรกทอรี app/views ซึ่งเก็บไฟล์เทมเพลตที่เป็นส่วนประกอบของวิวที่เกี่ยวข้องกับคอนโทรลเลอร์นั้น ไฟล์เหล่านี้ใช้ในการแสดงผลวิวที่เกิดจากแต่ละการกระทำของคอนโทรลเลอร์

มาดูว่า Rails ทำอะไรเมื่อสร้างทรัพยากรใหม่โดยใช้เจเนอเรเตอร์ scaffold:

$ bin/rails generate scaffold article
      [...]
      invoke  scaffold_controller
      create    app/controllers/articles_controller.rb
      invoke    erb
      create      app/views/articles
      create      app/views/articles/index.html.erb
      create      app/views/articles/edit.html.erb
      create      app/views/articles/show.html.erb
      create      app/views/articles/new.html.erb
      create      app/views/articles/_form.html.erb
      [...]

มีกฎในการตั้งชื่อวิวใน Rails โดยทั่วไปวิวจะใช้ชื่อเดียวกับการกระทำของคอนโทรลเลอร์ที่เกี่ยวข้อง ดังที่เราเห็นข้างต้น ตัวอย่างเช่น การกระทำ index ของ articles_controller.rb จะใช้ไฟล์วิว index.html.erb ในไดเรกทอรี app/views/articles HTML ที่ส่งกลับไปยังไคลเอนต์จะประกอบด้วยไฟล์ ERB นี้ เลเอาท์เทมเพลตที่ห่อหุ้ม และพาร์เชียลทั้งหมดที่วิวอาจอ้างถึง ในเอกสารนี้คุณจะพบคำอธิบายอย่างละเอียดเกี่ยวกับสามส่วนเหล่านี้

เหมือนกับที่กล่าวไว้ ผลลัพธ์ HTML สุดท้ายเป็นการรวมกันของสามองค์ประกอบของ Rails: เทมเพลต, พาร์เชียล, และ เลเอาท์ ด้านล่างนี้เป็นภาพรวมสั้น ๆ เกี่ยวกับแต่ละส่วน

3 เทมเพลต

เทมเพลตของ Action View สามารถเขียนได้หลายวิธี หากไฟล์เทมเพลตมีนามสกุล .erb แสดงว่าใช้ร่วมกับ ERB (Embedded Ruby) และ HTML หากไฟล์เทมเพลตมีนามสกุล .builder แสดงว่าใช้กับไลบรารี Builder::XmlMarkup

Rails รองรับระบบเทมเพลตหลายรูปแบบและใช้นามสกุลไฟล์เพื่อแยกแยะระหว่างพวกเขา ตัวอย่างเช่น ไฟล์ HTML ที่ใช้ระบบเทมเพลต ERB จะมีนามสกุล .html.erb

3.1 ERB

ในเทมเพลต ERB สามารถรวมรหัส Ruby ได้โดยใช้แท็ก <% %> และ <%= %> แท็ก <% %> ใช้ในการประมวลผลรหัส Ruby ที่ไม่ต้องการส่งคืนอะไรกลับ เช่นเงื่อนไข ลูป หรือบล็อก และแท็ก <%= %> ใช้เมื่อต้องการแสดงผล

พิจารณาลูปต่อไปนี้สำหรับชื่อ:

<h1>ชื่อของคนทั้งหมด</h1>
<% @people.each do |person| %>
  ชื่อ: <%= person.name %><br>
<% end %>

ลูปถูกตั้งค่าโดยใช้แท็กซ้อนกัน (<% %>) และชื่อถูกแทรกโดยใช้แท็กแทรกผลลัพธ์ (<%= %>) โปรดทราบว่านี่ไม่ใช่เพียงคำแนะนำในการใช้งาน: ฟังก์ชันแสดงผลทั่วไปเช่น print และ puts จะไม่ถูกแสดงในวิวด้วยเทมเพลต ERB ดังนั้นตัวอย่างนี้จะผิด:

<%# ผิด %>
สวัสดีคุณ <% puts "Frodo" %>

หากต้องการลดช่องว่างด้านหน้าและด้านหลัง คุณสามารถใช้ <%- -%> แทน <% และ %>

3.2 Builder

เทมเพลต Builder เป็นทางเลือกที่เป็นโปรแกรมมากกว่า ERB มีประโยชน์เฉพาะสำหรับการสร้างเนื้อหา XML ออกมา วัตถุ XmlMarkup ที่ชื่อว่า xml จะถูกสร้างขึ้นโดยอัตโนมัติและสามารถใช้ในเทมเพลตที่มีนามสกุล .builder

นี่คือตัวอย่างพื้นฐาน:

xml.em("เน้น")
xml.em { xml.b("เน้นและหนา") }
xml.a("ลิงค์", "href" => "https://rubyonrails.org")
xml.target("name" => "คอมไพล์", "option" => "เร็ว")

ผลลัพธ์ที่ได้คือ:

<em>เน้น</em>
<em><b>เน้นและหนา</b></em>
<a href="https://rubyonrails.org">ลิงค์</a>
<target option="เร็ว" name="คอมไพล์" />

เมื่อมีเมธอดที่มีบล็อก จะถูกจัดการเป็นแท็ก XML ที่มีแท็กซ้อนอยู่ในบล็อก ตัวอย่างเช่น:

xml.div {
  xml.h1(@person.name)
  xml.p(@person.bio)
}

จะสร้างผลลัพธ์เช่นนี้:

<div>
  <h1>David Heinemeier Hansson</h1>
  <p>A product of Danish Design during the Winter of '79...</p>
</div>

ด้านล่างนี้คือตัวอย่าง RSS ที่ใช้จริงบน Basecamp:

xml.rss("version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/") do
  xml.channel do
    xml.title(@feed_title)
    xml.link(@url)
    xml.description "Basecamp: Recent items"
    xml.language "en-us"
    xml.ttl "40"

    for item in @recent_items
      xml.item do
        xml.title(item_title(item))
        xml.description(item_description(item)) if item_description(item)
        xml.pubDate(item_pubDate(item))
        xml.guid(@person.firm.account.url + @recent_items.url(item))
        xml.link(@person.firm.account.url + @recent_items.url(item))
        xml.tag!("dc:creator", item.author_name) if item_has_creator?(item)
      end
    end
  end
end

3.3 Jbuilder

Jbuilder เป็น gem ที่ดูแลโดยทีม Rails และรวมอยู่ใน Gemfile ของ Rails โดยค่าเริ่มต้น มันคล้ายกับ Builder แต่ใช้สร้าง JSON แทน XML

หากคุณยังไม่มี คุณสามารถเพิ่มโค้ดด้านล่างนี้ใน Gemfile:

gem 'jbuilder'

Jbuilder object ที่ชื่อว่า json จะถูกสร้างขึ้นโดยอัตโนมัติและใช้ในเทมเพลตที่มีนามสกุล .jbuilder

นี่คือตัวอย่างพื้นฐาน:

json.name("Alex")
json.email("[email protected]")

จะสร้างผลลัพธ์เช่นนี้:

{
  "name": "Alex",
  "email": "[email protected]"
}

ดูเอกสาร Jbuilder สำหรับตัวอย่างและข้อมูลเพิ่มเติม

3.4 การเก็บแคชเทมเพลต

โดยค่าเริ่มต้น Rails จะคอมไพล์แต่ละเทมเพลตเป็นเมธอดเพื่อแสดงผล ในสภาพแวดล้อมการพัฒนา เมื่อคุณแก้ไขเทมเพลต Rails จะตรวจสอบเวลาแก้ไขของไฟล์และคอมไพล์ใหม่

4 Partial

Partial templates - ที่เรียกว่า "partials" - เป็นอุปกรณ์อีกอันหนึ่งที่ใช้ในกระบวนการแสดงผลเพื่อทำให้ง่ายต่อการจัดการ ด้วย partials คุณสามารถแยกโค้ดออกจากเทมเพลตหลักไปยังไฟล์ที่แยกออกและใช้ซ้ำได้ในทุกๆ เทมเพลต

4.1 การแสดงผล Partial

ในการแสดงผล partial เป็นส่วนหนึ่งของ view คุณใช้เมธอด render ภายใน view:

<%= render "menu" %>

นี้จะแสดงผลไฟล์ที่ชื่อ _menu.html.erb ที่จุดนั้นภายใน view ที่กำลังถูกแสดงผล โปรดทราบว่ามีอักขระขึ้นต้นด้วยเครื่องหมายขีดเส้นใต้: partials ถูกตั้งชื่อด้วยเครื่องหมายขีดเส้นใต้ขึ้นต้นเพื่อแยกจาก view ปกติ แม้ว่าจะใช้โดยไม่มีเครื่องหมายขีดเส้นใต้ นี่ยังเป็นจริงเมื่อคุณดึง partial จากโฟลเดอร์อื่น:

<%= render "shared/menu" %>

โค้ดนี้จะดึง partial จาก app/views/shared/_menu.html.erb

4.2 การใช้ Partial เพื่อทำให้ View ง่ายขึ้น

วิธีหนึ่งในการใช้ partials คือที่จะใช้เป็นเทียบเท่ากับ subroutine; วิธีการเคลื่อนย้ายรายละเอียดออกจาก view เพื่อให้คุณสามารถเข้าใจว่าเกิดอะไรขึ้นได้ง่ายขึ้น ตัวอย่างเช่น คุณอาจมี view ที่มีลักษณะดังนี้:

<%= render "shared/ad_banner" %>

<h1>Products</h1>

<p>Here are a few of our fine products:</p>
<% @products.each do |product| %>
  <%= render partial: "product", locals: { product: product } %>
<% end %>

<%= render "shared/footer" %>

ที่นี่ partial _ad_banner.html.erb และ _footer.html.erb อาจมีเนื้อหาที่ใช้ร่วมกันในหลายๆ หน้าของแอปพลิเคชันของคุณ คุณไม่จำเป็นต้องเห็นรายละเอียดของส่วนเหล่านี้เมื่อคุณตั้งใจทำงานกับหน้าเฉพาะ

4.3 render โดยไม่มี partial และ locals Options

ในตัวอย่างข้างต้น render ใช้ 2 options: partial และ locals แต่หาก เป็นตัวเลือกที่คุณต้องการส่งต่อเท่านั้นคุณสามารถข้ามการใช้ตัวเลือกเหล่านี้ได้ เช่น แทนที่จะ:

<%= render partial: "product", locals: { product: @product } %>

คุณยังสามารถทำได้:

<%= render "product", product: @product %>

4.4 ตัวเลือก as และ object

โดยค่าเริ่มต้น ActionView::Partials::PartialRenderer จะมีวัตถุของมันในตัวแปรโลคอลที่มีชื่อเดียวกับเทมเพลต ดังนั้น เมื่อได้รับ:

<%= render partial: "product" %>

ภายใน partial _product เราจะได้ @product ในตัวแปรโลคอล product เหมือนกับเราเขียน:

<%= render partial: "product", locals: { product: @product } %>

ตัวเลือก object สามารถใช้เพื่อระบุวัตถุที่จะแสดงผลใน partial โดยตรง มีประโยชน์เมื่อวัตถุของเทมเพลตอยู่ที่อื่น (เช่นในตัวแปรอินสแตนซ์อื่นหรือตัวแปรโลคอลอื่น)

ตัวอย่างเช่น แทนที่จะ:

<%= render partial: "product", locals: { product: @item } %>

เราจะทำ:

<%= render partial: "product", object: @item %>

ด้วยตัวเลือก as เราสามารถระบุชื่อตัวแปรโลคอลที่แตกต่างกันได้ ตัวอย่างเช่น หากเราต้องการให้เป็น item แทนที่ product เราจะทำ:

<%= render partial: "product", object: @item, as: "item" %>

นี่เทียบเท่ากับ erb <%= render partial: "product", locals: { item: @item } %>

4.5 การแสดงผลข้อมูลหลายรายการ

โดยทั่วไปแล้ว เราจะต้องการที่จะวนลูปผ่านรายการและแสดงผลข้อมูลในแต่ละรายการด้วย sub-template นี้เป็นรูปแบบการทำงานที่เรียกใช้เป็นเมธอดเดียวที่รับอาร์เรย์และแสดงผล sub-template สำหรับแต่ละองค์ประกอบในอาร์เรย์

ตัวอย่างการแสดงผลสินค้าทั้งหมด:

<% @products.each do |product| %>
  <%= render partial: "product", locals: { product: product } %>
<% end %>

สามารถเขียนใหม่ในบรรทัดเดียวได้:

<%= render partial: "product", collection: @products %>

เมื่อเรียกใช้ partial ด้วย collection แต่ละอินสแตนซ์ของ partial สามารถเข้าถึงสมาชิกของ collection ที่กำลังแสดงผลผ่านตัวแปรที่มีชื่อตาม partial ในกรณีนี้ partial คือ _product และภายใน partial นั้นคุณสามารถอ้างอิงไปยัง product เพื่อรับสมาชิกของ collection ที่กำลังแสดงผล

คุณสามารถใช้ไวยากรณ์ย่อสำหรับการแสดงผลข้อมูลหลายรายการ โดยสมมุติว่า @products เป็นคอลเลกชันของอินสแตนซ์ Product คุณสามารถเขียนดังนี้เพื่อให้ได้ผลลัพธ์เดียวกัน:

<%= render @products %>

Rails จะกำหนดชื่อของ partial ที่จะใช้โดยดูที่ชื่อโมเดลในคอลเลกชัน Product ในความเป็นจริงคุณยังสามารถแสดงผลข้อมูลหลายรายการที่ประกอบด้วยอินสแตนซ์ของโมเดลที่แตกต่างกันโดยใช้ไวยากรณ์ย่อนี้ และ Rails จะเลือก partial ที่เหมาะสมสำหรับแต่ละสมาชิกในคอลเลกชัน

4.6 การใช้งาน Spacer Templates

คุณยังสามารถระบุ partial ที่สองที่จะแสดงผลระหว่างอินสแตนซ์ของ partial หลักโดยใช้ตัวเลือก :spacer_template:

<%= render partial: @products, spacer_template: "product_ruler" %>

Rails จะแสดงผล partial _product_ruler (โดยไม่มีข้อมูลที่ส่งไปยังมัน) ระหว่างแต่ละคู่ของ partial _product

4.7 Strict Locals

โดยค่าเริ่มต้น template จะยอมรับ locals ใดๆ เป็น keyword arguments ในการกำหนดว่า template ยอมรับ locals ใด ให้เพิ่มคอมเมนต์ magic locals:

<%# locals: (message:) -%>
<%= message %>

ค่าเริ่มต้นสามารถกำหนดได้ดังนี้:

<%# locals: (message: "Hello, world!") -%>
<%= message %>

หรือ locals สามารถปิดใช้งานได้ทั้งหมด:

<%# locals: () %>

5 Layouts

Layouts สามารถใช้ในการแสดงผล template ที่เป็นร่วมกันรอบผลลัพธ์ของการดำเนินการของคอนโทรลเลอร์ใน Rails โดยทั่วไปแล้ว แอปพลิเคชัน Rails จะมีเลย์เอาท์สองรูปแบบที่หน้าจอจะถูกแสดงภายใน เช่น ไซต์อาจมีเลย์เอาท์สำหรับผู้ใช้ที่เข้าสู่ระบบและอีกเลย์เอาท์สำหรับการตลาดหรือการขายของไซต์ เลย์เอาท์สำหรับผู้ใช้ที่เข้าสู่ระบบอาจรวมการนำทางระดับบนที่ควรมีอยู่ในหลายๆ การดำเนินการของคอนโทรลเลอร์ เลย์เอาท์สำหรับการขายของแอป SaaS อาจรวมการนำทางระดับบนสำหรับสิ่งเช่นหน้า "ราคา" และ "ติดต่อเรา" คุณคาดหวังว่าแต่ละเลย์เอาท์จะมีลักษณะและความรู้สึกที่แตกต่างกัน คุณสามารถอ่านเพิ่มเติมเกี่ยวกับเลย์เอาท์ใน Layouts and Rendering in Rails guide.

5.1 Partial Layouts

Partial สามารถใช้เลย์เอาท์ของตัวเองได้ ลักษณะเลย์เอาท์เหล่านี้แตกต่างจากเลย์เอาท์ที่ใช้กับการดำเนินการของคอนโทรลเลอร์ แต่พวกเขาทำงานในลักษณะที่คล้ายกัน

เราสมมุติว่าเรากำลังแสดงบทความบนหน้าเว็บซึ่งควรจะถูกห่อหุ้มด้วย div เพื่อเป็นวัตถุประสงค์ในการแสดงผล ก่อนอื่น เราจะสร้าง Article ใหม่:

Article.create(body: 'Partial Layouts are cool!')

ใน template show เราจะแสดงผล partial _article ที่ถูกห่อหุ้มด้วยเลย์เอาท์ box:

articles/show.html.erb

<%= render partial: 'article', layout: 'box', locals: { article: @article } %>

เลย์เอาท์ box จะห่อหุ้ม partial _article ด้วย div:

articles/_box.html.erb

<div class='box'>
  <%= yield %>
</div>

โปรดทราบว่า partial layout สามารถเข้าถึงตัวแปร local article ที่ถูกส่งเข้าไปในการเรียกใช้ render อย่างไรก็ตาม ไม่เช่นนั้น เหมือนกับเลย์เอาท์ทั่วไปในแอปพลิเคชัน แต่ partial layout ยังคงมีคำนำหน้าด้วยเครื่องหมาย underscore

คุณยังสามารถแสดงผลบล็อกของโค้ดภายใน partial layout แทนการเรียกใช้ yield ตัวอย่างเช่น หากเราไม่มี partial _article เราสามารถทำได้ดังนี้:

articles/show.html.erb

<% render(layout: 'box', locals: { article: @article }) do %>
  <div>
    <p><%= article.body %></p>
  </div>
<% end %>

สมมุติว่าเราใช้ partial _box เดียวกับตัวอย่างด้านบน สิ่งนี้จะให้ผลลัพธ์เดียวกับตัวอย่างก่อนหน้านี้

6 View Paths

เมื่อแสดงผลการตอบสนอง คอนโทรลเลอร์จำเป็นต้องแก้ไขที่ตั้งของวิวต่างๆ โดยค่าเริ่มต้น มันจะมองหาในไดเรกทอรี app/views เท่านั้น เราสามารถเพิ่มตำแหน่งอื่น ๆ และกำหนดลำดับความสำคัญให้กับการแก้ไขเส้นทางโดยใช้วิธีการ prepend_view_path และ append_view_path

6.1 Prepend View Path

นี้สามารถมีประโยชน์เช่นเมื่อเราต้องการวางวิวภายในไดเรกทอรีที่แตกต่างกันสำหรับโดเมนย่อย

เราสามารถทำได้โดยใช้:

prepend_view_path "app/views/#{request.subdomain}"

จากนั้น Action View จะค้นหาในไดเรกทอรีนี้ก่อนเมื่อแก้ไขวิว

6.2 Append View Path

เช่นเดียวกัน เราสามารถเพิ่มเส้นทางได้:

append_view_path "app/views/direct"

นี้จะเพิ่ม app/views/direct ไปยังสิ้นสุดของเส้นทางการค้นหา

7 Helpers

Rails มีเมธอดช่วยเหลือมากมายที่ใช้กับ Action View ซึ่งรวมถึงเมธอดสำหรับ:

  • จัดรูปแบบวันที่ เป็นต้น
  • สร้างลิงก์ HTML ไปยังรูปภาพ วิดีโอ สไตล์ชีต เป็นต้น
  • ทำความสะอาดเนื้อหา
  • สร้างแบบฟอร์ม
  • จัดการเนื้อหาในภาษาท้องถิ่น

คุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับ helpers ใน Action View Helpers Guide และ Action View Form Helpers Guide.

8 Localized Views

Action View สามารถแสดงเทมเพลตที่แตกต่างกันไปขึ้นอยู่กับภาษาปัจจุบันได้

ตัวอย่างเช่น สมมติว่าคุณมี ArticlesController ที่มีการดำเนินการแสดงผล โดยค่าเริ่มต้นการเรียกใช้การดำเนินการนี้จะแสดงผล app/views/articles/show.html.erb แต่ถ้าคุณตั้งค่า I18n.locale = :de แล้ว app/views/articles/show.de.html.erb จะถูกแสดงแทน หากไม่มีเทมเพลตที่แปลงภาษาให้ใช้ จะใช้เทมเพลตที่ไม่มีการตกแต่งแทน นั่นหมายความว่าคุณไม่จำเป็นต้องให้เทมเพลตที่แปลงภาษาสำหรับทุกกรณี แต่ถ้ามีจะถูกใช้งานและใช้งานได้

คุณสามารถใช้เทคนิคเดียวกันเพื่อแปลภาษาไฟล์ช่วยเหลือในไดเรกทอรีสาธารณะของคุณ ตัวอย่างเช่น การตั้งค่า I18n.locale = :de และการสร้าง public/500.de.html และ public/404.de.html จะช่วยให้คุณมีหน้าช่วยเหลือที่แปลภาษาได้

เนื่องจาก Rails ไม่จำกัดสัญลักษณ์ที่คุณใช้ในการตั้งค่า I18n.locale คุณสามารถใช้ระบบนี้เพื่อแสดงเนื้อหาที่แตกต่างกันขึ้นอยู่กับอะไรก็ได้ที่คุณชอบ ตัวอย่างเช่น สมมติว่าคุณมีผู้ใช้ "ผู้เชี่ยวชาญ" บางคนที่ควรเห็นหน้าเพจที่แตกต่างกันจากผู้ใช้ "ปกติ" คุณสามารถเพิ่มส่วนต่อไปนี้ใน app/controllers/application_controller.rb:

before_action :set_expert_locale

def set_expert_locale
  I18n.locale = :expert if current_user.expert?
end

จากนั้นคุณสามารถสร้างวิวพิเศษเช่น app/views/articles/show.expert.html.erb ซึ่งจะแสดงเฉพาะผู้ใช้ที่เชี่ยวชาญ

คุณสามารถอ่านเพิ่มเติมเกี่ยวกับ Rails Internationalization (I18n) API ที่นี่

ข้อเสนอแนะ

คุณสามารถช่วยปรับปรุงคุณภาพของคู่มือนี้ได้

กรุณาช่วยเพิ่มเติมหากพบข้อผิดพลาดหรือข้อผิดพลาดทางความจริง เพื่อเริ่มต้นคุณสามารถอ่านส่วน การสนับสนุนเอกสาร ของเราได้

คุณอาจพบเนื้อหาที่ไม่สมบูรณ์หรือเนื้อหาที่ไม่ได้อัปเดต กรุณาเพิ่มเอกสารที่ขาดหายไปสำหรับเนื้อหาหลัก โปรดตรวจสอบ Edge Guides ก่อนเพื่อตรวจสอบ ว่าปัญหาได้รับการแก้ไขหรือไม่ในสาขาหลัก ตรวจสอบ คู่มือแนวทาง Ruby on Rails เพื่อดูรูปแบบและกฎเกณฑ์

หากคุณพบข้อผิดพลาดแต่ไม่สามารถแก้ไขได้เอง กรุณา เปิดปัญหา.

และสุดท้าย การสนทนาใด ๆ เกี่ยวกับ Ruby on Rails เอกสารยินดีต้อนรับที่สุดใน เว็บบอร์ดอย่างเป็นทางการของ Ruby on Rails.