Richlewis
Richlewis

Reputation: 15394

Rails Association clarification

I am looking to confirm whether the following association declaration's would work of if there is a more efficient way of doing this.

I have a Animal Model and where you can create a dog, cat, rabbit etc, I also need to specify what breed the animal is, so i thought set up a model for each animal breed type, so DogBreed for example and then Cat Breed.

I was thinking that each animal can only have one breed, so would something like this work

 class Animal
   has_one :dog_breed
   has_one :cat_breed
 end

class DogBreed
  belongs_to :animal
end

class CatBreed
  belongs_to :animal
end

Colums for each model would be

Animal
  name
  description
  size
  breed

DogBreed
  name

CatBreed
  name

is there a better way to approach this?

Also i will be adding accepts_nested_attributes_for to the animal model for each breed model

Thanks

Upvotes: 2

Views: 61

Answers (1)

Richard Peck
Richard Peck

Reputation: 76784

STI

You're looking for Single Table Inheritance:

#app/models/animal.rb
class Animal < ActiveRecord::Base
   has_many :x
end

#app/models/dog.rb
class Dog < Animal
end

#app/models/cat.rb
class Cat < Animal
end

As the name "Single Table Inheritance" suggests, your "dependent" models will inherit from. This means you will be able to store a central table called animals, into which you'll need to add a type column:

$ rails g migration AddTypeToAnimals

#db/migrate/add_type_to_animals.rb
class AddTypeToAnimals
   def change
      add_column :animals, :type, :string
   end
end

--

Fix

The way this works is actually very simple.

You can call your Dog and Cat models with impunity (no changes out of the scope of "normal" Rails work). The type column will be populated automatically:

#app/controllers/dogs_controller.b
class DogsController < ApplicationController
   def new
      @owner_dog = Dog.new
   end

   def create
      @owner_dog = Dog.new dog_params
      @owner_dog.save
   end

   private

   def dog_params
      params.require(:dog).permit(:x,:y,:z)
   end
end

Update

From our Skype talk, you'll probably want to do this:

#app/models/animal.rb
class Animal < ActiveRecord::Base
   #fields id | breed_id | name | created_at | updated_at
   belongs_to :breed
   delegate :name, to: :breed, prefix: true
end

#app/models/breed.rb
class Breed < ActiveRecord::Base
   #fields id | name | created_at | updated_at
   has_many :animals
end

This will give you the ability to use the following:

#app/controllers/animals_controller.rb
class AnimalsController < ApplicationController
   def new 
      @animal = Animal.new
   end

   def create 
      @animal = Animal.new animal_params
   end

   private

   def animal_params
      params.require(:animal).permit(:name, :breed_id)
   end
end

#app/views/animals/new.html.erb
<%= form_for @animal do |f| %>
   <%= f.text_field :name %>
   <%= f.collection_select :breed_id, Breed.all, :id, :name %>
   <%= f.submit %>
<% end %>

Upvotes: 3

Related Questions