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

13 篇文章 0 订阅

Time to continue learning about Single Table Inheritance with Ruby on Rails.

Learn how to implement STI with Rails with this free ebook

In this article, we are going to see how to create a common controller for our models (Animal, Lion, etc). We will also need to create the corresponding routes and add some helpers to generate the right paths. If you don’t have the code from the first part, you can get it here.

The common controller

Time to start working ! First, we have to generate the common controller for our models. The name is going to be AnimalsController which matches our parent model.

rails g controller AnimalsController index show new edit create update destroy

Define the routes

Let’s move to the routes file and define our routes. First, remove the lines generated by rails since we are going to use resources :

# Remove these lines from config/routes.rb
get "animals/index"
# Code hidden for brevity
get "animals/destroy"

Define the root of our app and the routes for Animals :

# config/routes.rb
Sti::Application.routes.draw do
 resources :animals
 root 'animals#index'
end

Setup the index action and the corresponding view

Fire up your server and access localhost:3000 and you will see, well nothing. We should add some content to our index view, maybe the list of all the animals in the database. To provide this list to the view, we need to add some simple code to our controller :

# app/controllers/animals_controller.rb
def index
  @animals = Animal.all
end

And copy/paste (or retype it, totally up to you) the following in 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>

The view still looks pretty bad huh, but whatever, it’s not a design tutorial. You are free to add some css (and you can even pull request on [the repo][2], I will definitely merge it if it looks good).

Now that we have a basic way to show our data, we can start playing with Single Table Inheritance. In the first part, we created one table animals and one model Animal. We also created 3 other models (Lion, Meerkat, WildBoars) that inherit from Animal and all live happily in the same table. Thanks to that, we avoided repeating code at the model level. We can follow the DRY rule at the controller level by using a unique controller for all our STI models.

Routes and STI

After a bit of code, the index action of the Animals controller will be able to show either all the animals or only the animals of a specific race. To do this, the controller need to know which race is requested. Thanks to Rails, we can define a default parameter in our routes.

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

See the type key ? That’s the trick. Everytime we access /lions/*, Rails will add a parameter in paramswith the key type. So, for each model that inherit from Animal, we define resource routes and specify that they have to use the animals controller. We also add the corresponding type.

We can now extract the type value in the controller with the following methods :

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

Basically, before any action we assign the value of the race params, or Animal if no race is passed, to the variable @race so our views can access it. We can now change the Animal.all to race_class.all. The method race_class is going to send back the constantized parameter type like Lion for example.

def index
  @animals = race_class.all
end

Warm Up

If you access http://localhost:3000, you will have the list of all animals. But if you access http://localhost:3000/lions or http://localhost:3000/meerkats, you only get the list of the specified animal. Wonderful, isn’t it ?!

That’s it for this article. In the next part, we are going to add dynamic paths and the missing views !

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值