[ROR]Single Table Inheritance with Rails 4 (Part 3)

13 篇文章 0 订阅

In the last article, we created our controller and define the index view. In this one, we are going to add the missing views and see some tricks to handle paths for STI models.

Learn how to implement STI with Rails with this free ebook

Dynamic paths helper

Before we implement the other views, we need a way to create dynamic paths based on the race. To do that, we can use the following helpers method.

# 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

The show must go on

Update the index.html to integrate this new method :

<td><%= link_to 'Show', sti_animal_path(animal.race, animal) %></td>

And create the file show.html.erb in views/animals :

<h1>Hi, I'm a <%= @animal.race %>.</h1>
<p>My name is <%= @animal.name %></p>
<%= @animal.talk %>

Last step before seeing our show action, we need to define @animal in the controller. To do that, we are going to add a callback before_action before every action where we will need @animal to be defined :

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

Now refresh the webpage, click on show and tadaa ! It’s going to take you to the right animal with the right path (lions/meerkats/wild_boars).

Sharing the index view

We are almost done, first let’s improve our index page. For each animal in the table, we are going to add a link to the list of animals of the same species :

<td><%= link_to "See all #{animal.race.pluralize}", sti_animal_path(animal.race) %></td>

And a way to show the list of all animals :

    [...]
    </tbody>
</table>

<%= link_to 'See all animals', sti_animal_path %>

Finally, we need a link to create a new animal :

[...]
<%= link_to 'See all animals', sti_animal_path %>
<%= link_to "New #{@race}", sti_animal_path(@race, nil, :new) %>

Play a bit with the app, you should be able to navigate between all the animals and specific races. We better add the new view now since we just created the link to get there !

Creating animals

The new view is quite simple, all the logic will be setup in the form partial :

# views/animals/new.html.erb
<h1>New <%=  "#{@race.capitalize}" %></h1>
<%= render 'form' %>
<%= link_to 'Back', sti_animal_path(@race) %>

Also, we need to instantiate a new object in the action new of our controller :

# controllers/animals_controller.rb
def new
  @animal = race_class.new
end

Now the form :

<%= 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 %>

Okay, now you should be able to access the new page and fill the form. If you play a bit with the path, you will notice that the select box for the race is only enabled if you create a new Animal. If you try to create a new Lion (/lions/new), the select box will be selected by default and will be disabled.

Strong parameters for Animal

Before we actually create animals with our form, we need to define the parameters that can be passed to our animal. This is a Rails 4 new feature, if you want more information, check out the doc.

As you can see in the following code, we added a method called animal_params which define the three parameters that we want to allow for the model Animal. We also added the code for the create action :

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

Updating and deleting animals

Now let’s add the code for the two missing actions, update and destroy, and the edit view. First, we are going to put the links to access them in the index page :

  <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>

Then, we define the actions in the 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

And finally, the edit view :

#views/animals/edit.html.erb
<h1>Editing <%= "#{@race}" %></h1>
<%= render 'form' %>
<%= link_to 'Back', sti_animal_path(@race) %>

And that’s it ! We are done.

Source code

The code is available on Github.

Warm Up

Through this set of tutorials, I hope you understood what can be done with Single Table Inheritance and how it can prevent you from having similar controllers. You won’t use STI everyday, but when you need it you will be happy to find it ;)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值