Models, Views, and Controllers (+ Minitest)
MVC Pattern
- Model จะอยู่ในโฟลเดอร์
app/models - Controller จะอยู่ในโฟลเดอร์
app/controllers - View จะอยู่ในโฟลเดอร์
app/views
ไฟล์ config/routes.rb จะเป็นไฟล์สำหรับ Routes เราสามารถดู Routes ทั้งหมดได้โดยใช้คำสั่ง
Rails มี generator คอยช่วยให้เราไม่ต้องเขียนโค้ดเยอะ
หรือ
คำสั่งนี้จะไปแก้ไฟล์ config/routes.rb ให้เราด้วย ลองเข้าหน้า http://127.0.0.1:3000/home/index ก็จะเห็นหน้าที่เพิ่มเข้ามา
ถ้าอยากให้หน้า Home ของเราเป็นหน้าแรกของเว็บ เราจะเพิ่มบรรทัดด้านล่างนี้เข้าไปที่ไฟล์ config/routes.rb
แล้วลองเข้า http://127.0.0.1:3000
Create a New Page Manually
สร้างไฟล์ app/views/home/about.html.erb
สร้าง about ใน app/controllers/home_controller.rb
แก้ config/routes.rb
Rails.application.routes.draw do
get 'home/index'
get 'home/about'
root 'home#index'
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
# Defines the root path route ("/")
# root "articles#index"
end
ลองเข้าหน้า http://127.0.0.1:3000/home/about
Partial Template
สร้างไฟล์ app/views/home/_header.html.erb
ไปแก้ไฟล์ app/views/layout/application.html.erb
Rails จะรู้ว่าตอน render จะไปหยิบ _header.html.erb เอง
Navigating with link_to
ของ root ต้องใช้ root_path
ของหน้าอื่นๆ เราสามารถใช้ชื่อ controller ได้เลย เช่น controller home มี method ชื่อ about ตัว route ก็จะเป็น home_about_path สังเกตว่า suffix จะเป็น _path เสมอ
Refer to Variable in Controller from View
app/controllers/home_controller.rb
class HomeController < ApplicationController
def index
end
def about
# instance variable can be called in view
@about_me = "My name is Kan Ouivirach"
end
end
app/views/home/about.html.erb
Adding Project to the App
Creating a Controller
เพิ่มโค้ดนี้ใน config/routes.rb
เราจะให้ลิ้งค์ไปที่ Action ที่ชื่อ index
Creating a Model
พวก Method ต่าง ๆ จะอยู่ใน ApplicationRecord อยู่แล้ว
Creating a View
สร้างไฟล์ app/views/project/index.html.erb
<h1>Projects</h1>
<ul>
<% @projects.each do |project| %>
<li><%= project.name %></li>
<% end %>
</ul>
ลองเพิ่มข้อมูลใน Rails Console
Adding CRUD Actions
ถ้าเราอยากจะดูข้อมูลแต่ละข้อมูลแบบ Dynamic เพิ่ม config/routes.rb
เราจะได้ params เข้ามาใน Action ที่ชื่อ show ให้เราเพิ่มโค้ดตามนี้
ให้เพิ่มไฟล์ show.html.erb
ทำลิ้งค์ที่หน้า Index เราสามารถใช้ link_to ได้ ให้แก้โค้ดให้เป็นตามนี้
New
ต้องมาก่อน Route ของ show ด้วย เพราะว่า Routes จะ Match ตาม Order จากบนลงล่าง
เพิ่ม Action new ให้มีแค่ Initiation
สร้างไฟล์ new.html.erb
<h1>New Project</h1>
<%= form_with model: @project do |f| %>
<div class="field">
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<div class="actions">
<%= f.submit "Create Project" %>
</div>
<% end %>
def create
@project = Project.new(project_params)
if @project.save
redirect_to project_path(@project)
else
render :new
end
end
เพื่อบอก Rails ให้มีแค่ name เท่านั้นที่ยอมให้ผ่าน
เพิ่ม Validation
class Project < ApplicationRecord
validates :name, presence: true
# validates :name, presence: { message: "Did you forget to add a name?" }
end
เพิ่มโค้ดนี้ใน Form
<% if @project.errors.any? %>
<div class="errors">
<h2><%= pluralize(@project.errors.count, "error") %> prohibited this project from being saved:</h2>
<ul>
<% @project.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
ไฟล์ edit.html.erb ใช้เหมือน new.html.erb เลย
def update
@project = Project.find(params[:id])
if @project.update(project_params)
redirect_to project_path(@project)
else
render :edit, status: unprocessable_entity
end
end
ใช้ Partials
เอา Form ทั้งหมดไปใช้ _form.html.erb
ปรับไฟล์หลักให้เหลือ
ส่ง project เข้าไป ดังนั้นใน _form.html.erb ให้ลบ @ ออกด้วย
Flash message
เพิ่มโค้ดด้านล่างนี้
ไว้ที่ application.html.erb
def destroy
@project = Project.find(params[:id])
@project.destroy
flash[:notice] = "Project deleted."
redirect_to projects_path
end
เปลี่ยน Routes ทั้ง 7 ให้เหลือแค่นี้ได้เลย
Migrations
Associations
Todos <> Projects
class Project < ApplicationRecord
has_many :todos, dependent: :destroy
validates :name, presence: true
end
เพิ่มฟิลด์ในไฟล์ app/views/todos/_form.html.erb
<div>
<%= form.label :completed, style: "display: block" %>
<%= form.check_box :completed %>
</div>
<div>
<%= form.label :priority, style: "display: block" %>
<%= form.number_field :priority %>
</div>
<div>
<%= form.label :project_id, style: "display: block" %>
<%= form.collection_select :project_id, Project.all, :id, :name, prompt: "Select a project" %>
</div>
ต้องอัพเดท Controller ด้วย เพิ่มไปใน Strong Parameters
app/views/todos/_todo.html.erb
<p>
...
</p>
<p>
<strong>Project:</strong>
<%= link_to todo.project.name, project_path(todo.project) %>
</p>
เพิ่มโค้ดด้านล่างนี้ app/view/projects/show.html.erb