Single Table Inheritance trong Rails 4 (Phần 2)
Bài đăng này đã không được cập nhật trong 8 năm
Trong bài viết này, chúng ta sẽ đi tìm hiểu xem làm thế nào để tạo ra một controller chung
cho các model (Animal, Lion, ...). Chúng ta cần phải tạo routes
tương ứng và thêm một số helper để tạo ra đường dẫn đúng. Nếu bạn không có sẵn code từ phần 1, hãy xem lại để có thể bắt đầu ở đây.
Controller chung
Đầu tiên, chúng ta tạo controller chung cho các model là AnimalsController tương ứng với model cha.
rails g controller AnimalsController index show new edit create update destroy
Thiết lập routes
Di chuyển đến file routes.rb
và xác định các đường dẫn:
# Remove these lines from config/routes.rb
get "animals/index"
# Code hidden for brevity
get "animals/destroy"
Xác định root của app và routes cho Animals:
# config/routes.rb
Sti::Application.routes.draw do
resources :animals
root 'animals#index'
end
Thiết lập hành động index và view tương ứng
Chạy server và truy cập localhost: 3000
và bạn sẽ thấy, không có gì . Chúng ta cần thêm nội dung cho view index, có thể là danh sách của tất cả các animal trong database. Để cung cấp danh sách này, ta cần thêm vào controller dòng sau:
# app/controllers/animals_controller.rb
def index
@animals = Animal.all
end
Và copy/paste đoạn code sau vào animals/index.html.erb
:
# app/views/animals/index.html.erb
<h1>The Lion Tribe</h1>
<table>
<thead>
<tr>
<th>Name</th>
<th>Race</th>
<th>Age</th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<% @animals.each do |animal| %>
<tr>
<td><%= animal.name %></td>
<td><%= animal.race %></td>
<td><%= animal.age %></td>
<td><%= link_to 'Show', "" %></td>
<td><%= link_to 'Edit', "" %></td>
<td><%= link_to 'Destroy', "", method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
Bây giờ chúng ta có một cách cơ bản để hiển thị dữ liệu là bắt đầu với Single Table Inheritance
. Trong phần 1, ta đã tạo ra một bảng animals và một model Animal. Ta cũng tạo ra 3 model khác (Lion, Meerkat, WildBoars) là các model kế thừa từ model Animal và tất cả dùng chung 1 bảng. Nhờ đó, chúng ta tránh lặp lại code. Ta có thể tuân theo các quy tắc DRY trong controller bằng cách sử dụng một controller duy nhất cho tất cả các mô hình STI.
Routes và STI
Hành động index của controller Animals sẽ hiển thị tất cả các animal hoặc 1 loại animal. Với Rails, ta có thể xác định bằng cách thêm một param mặc định vào các đường dẫn:
# config/routes.rb
resources :animals
resources :lions, controller: 'animals', type: 'Lion'
resources :meerkats, controller: 'animals', type: 'Meerkat'
resources :wild_boars, controller: 'animals', type: 'WildBoar'
root 'animals#index'
Là một tip nhỏ khi sử dụng type
. Mỗi khi chúng ta truy cập /lions/*
, Rails sẽ thêm một param type
vào. Vì vậy, đối với mỗi model kế thừa ta thêm type tương ứng vào đường dẫn.
Bây giờ chúng ta có thể sử dụng các giá trị type trong controller:
class AnimalsController < ApplicationController
before_action :set_race
def index
@animals = Animal.all
end
# Code hidden for brivety
private
def set_race
@race = race
end
def race
Animal.races.include?(params[:type]) ? params[:type] : "Animal"
end
def race_class
race.constantize
end
end
Về cơ bản, trước bất kỳ một hành động nào đó chúng ta xác định giá trị race
bằng params[:type], hoặc bằng "Animal" nếu không có params[:type], đặt thêm biến @race để có thể dùng trong view. Bây giờ chúng ta có thể thay đổi Animal.all bằng race_class.all
.
def index
@animals = race_class.all
end
Nếu bạn truy cập vào http://localhost:3000
, bạn sẽ có một danh sách của tất cả các animal. Nhưng nếu bạn truy cập vào http://localhost:3000/lions
hoặc http://localhost:3000/meerkats
, bạn chỉ nhận được danh sách các animal với type tương ứng.
Đây là tất cả nội dung của bài viết này. Trong phần tiếp theo chúng ta sẽ thêm đường dẫn động và các view còn thiếu!
Tài liệu dịch: https://samurails.com/tutorial/single-table-inheritance-with-rails-4-part-2/
Link dịch phần 1: https://viblo.asia/march_vu/posts/pVYRPJZkG4ng
All rights reserved