Single Table Inheritance trong Rails 4 (Phần3)
Trong bài viết trước, chúng tôi đã hướng dẫn việc tạo controller chung và xác định view index. Trong bài này, chúng tôi sẽ bổ sung thêm các view còn thiếu và thấy một số thủ thuật để xử lý đường dẫn cho các model STI. Tạo các đường dẫn động trong file helpers Trước khi thêm các view khác, ta ...
Trong bài viết trước, chúng tôi đã hướng dẫn việc tạo controller chung và xác định view index. Trong bài này, chúng tôi sẽ bổ sung thêm các view còn thiếu và thấy một số thủ thuật để xử lý đường dẫn cho các model STI.
Tạo các đường dẫn động trong file helpers
Trước khi thêm các view khác, ta cần tạo ra các đường dẫn động dựa theo race. Để làm điều đó, chúng ta có thể sử dụng các method sau trong helpers.
# helpers/animals_helper.rb # Returns a dynamic path based on the provided parameters def sti_animal_path(race = "animal", animal = nil, action = nil) send "#{format_sti(action, race, animal)}_path", animal end def format_sti(action, race, animal) action || animal ? "#{format_action(action)}#{race.underscore}" : "#{race.underscore.pluralize}" end def format_action(action) action ? "#{action}_" : "" end
** Tạo đường dẫn và file view cho action show**
Update index.html với method mới này:
<td><%= link_to 'Show', sti_animal_path(animal.race, animal) %></td>
Và tạo ra file show.html.erb trong views/animals:
<h1>Hi, I'm a <%= @animal.race %>.</h1> <p>My name is <%= @animal.name %></p> <%= @animal.talk %>
Bước cuối cùng, chúng ta cần phải xác định @animal trong controller. Để làm điều đó, chúng ta sẽ thêm before_action gọi lại trước mỗi action mà chúng ta cần xác định @animal:
class AnimalsController < ApplicationController before_action :set_animal, only: [:show, :edit, :update, :destroy] before_action :set_race def index @animals = race_class.all end def show end # Code hidden for brivety private # Code hidden for brivety def set_animal @animal = race_class.find(params[:id]) end end
Bây giờ refresh lại trang, click vào show! Nó sẽ chuyển đến trang show đúng loại animal tương ứng với đường đẫn (lions/meerkats/wild_boars).
Thêm đường dẫn trong index view
Bổ sung thêm một số đường dẫn đến danh sách từng loại animal vào trang index:
<td><%= link_to "See all #{animal.race.pluralize}", sti_animal_path(animal.race) %></td>
Và đường dẫn để hiển thị danh sách của tất cả các loại animal:
[...] </tbody> </table> <%= link_to 'See all animals', sti_animal_path %>
Cuối cùng, chúng ta cần một link để tạo animal:
[...] <%= link_to 'See all animals', sti_animal_path %> <%= link_to "New #{@race}", sti_animal_path(@race, nil, :new) %>
Hãy test một chút với những gì bạn vừa làm được ^^
Tạo Animal
View cho trang new khá đơn giản, tất cả các logic sẽ được thiết lập trong partial form:
# views/animals/new.html.erb <h1>New <%= "#{@race.capitalize}" %></h1> <%= render 'form' %> <%= link_to 'Back', sti_animal_path(@race) %>
Ngoài ra, chúng ta cần tạo thêm action new trong animals_controller:
# controllers/animals_controller.rb def new @animal = race_class.new end
_form.rb :
<%= form_for(@animal) do |f| %> <% if @animal.errors.any? %> <div id="error_explanation"> <h2><%= pluralize(@animal.errors.count, "error") %> prohibited this animal from being saved:</h2> <ul> <% @animal.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %> <div class="field"> <%= f.label :name %><br> <%= f.text_field :name %> </div> <div class="field"> <%= f.label :race %><br> <%= f.select :race, Animal.races.map {|r| [r.humanize, r.camelcase]}, {}, disabled: @race != "Animal" %> </div> <div class="field"> <%= f.label :age %><br> <%= f.text_field :age %> </div> <div class="actions"> <%= f.submit %> </div> <% end %>
Bây giờ chúng ta có thể tạo được animal. Select_box race chỉ enabled khi bạn tạo Animal, còn nếu bạn tạo một Lion (/lions/new) thì select_box sẽ được thiết lập giá trị mặc định là lion và disabled.
Strong parameters Animal
Bạn có thể thấy trong đoạn code dưới đây, chúng tôi đã thêm một method để xác định các params cho phép tạo cho model Animal. Action create cũng được thafAnimalory đổi:
class AnimalsController < ApplicationController # Code hidden for brievety def create @animal = Animal.new(animal_params) if @animal.save redirect_to @animal, notice: "#{race} was successfully created." else render action: 'new' end end # Code hidden for brievety private # Code hidden for brievety def animal_params params.require(race.underscore.to_sym).permit(:name, :race, :age) end end
Thêm action update and delete
Đầu tiên, sẽ đặt các đường dẫn để dễ dàng truy cập các action:
<td><%= link_to 'Edit', sti_animal_path(animal.race, animal, :edit) %></td> <td><%= link_to 'Destroy', sti_animal_path(animal.race, animal), method: :delete, data: { confirm: 'Are you sure?' } %></td>
Sau đó, chúng tôi xác định các action trong controller:
def update if @animal.update(animal_params) redirect_to @animal, notice: "#{race} was successfully created." else render action: 'edit' end end def destroy @animal.destroy redirect_to animals_url end
Cuối cùng là thêm file edit.html.erb :
#views/animals/edit.html.erb <h1>Editing <%= "#{@race}" %></h1> <%= render 'form' %> <%= link_to 'Back', sti_animal_path(@race) %>
Kết:
Thông qua hướng dẫn này, tôi hy vọng bạn hiểu những gì có thể được thực hiện với Single Table Inheritance và làm thế nào nó có thể giúp bạn hạn chế sử dụng các controller tương tự nhau.
Tài liệu dịch: https://samurails.com/tutorial/single-table-inheritance-with-rails-4-part-3/
Link dịch phần 1: https://viblo.asia/march_vu/posts/pVYRPJZkG4ng
Link dịch phần 2: https://viblo.asia/march_vu/posts/WkwGnWq3v75g