Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invalid single-table inheritance type: Rails

I'm getting this error when trying to create a new Product in my Rails application.

Invalid single-table inheritance type: Movie is not a subclass of Product

How can I resolve this?

enter image description here

controller

class ProductsController < ApplicationController
  before_action :set_product, only: [:show, :edit, :update, :destroy]

  # GET /products
  # GET /products.json
  def index
    @products = Product.all
  end

  # GET /products/1
  # GET /products/1.json
  def show
  end

  # GET /products/new
  def new
    @product = Product.new
  end

  # GET /products/1/edit
  def edit
  end

  # POST /products
  # POST /products.json
  def create
    @product = Product.new(product_params)

    respond_to do |format|
      if @product.save
        format.html { redirect_to @product, notice: 'Product was successfully created.' }
        format.json { render action: 'show', status: :created, location: @product }
      else
        format.html { render action: 'new' }
        format.json { render json: @product.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /products/1
  # PATCH/PUT /products/1.json
  def update
    respond_to do |format|
      if @product.update(product_params)
        format.html { redirect_to @product, notice: 'Product was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: 'edit' }
        format.json { render json: @product.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /products/1
  # DELETE /products/1.json
  def destroy
    @product.destroy
    respond_to do |format|
      format.html { redirect_to products_url }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_product
      @product = Product.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def product_params
      params.require(:product).permit(:title, :artist, :type, :release_date, :category, :publisher, :format, :description, :sale_price, :rental_price)
    end
end

migration

class CreateProducts < ActiveRecord::Migration
  def change
    create_table :products do |t|
      t.string :title
      t.string :artist
      t.string :type
      t.date :release_date
      t.string :category
      t.string :publisher
      t.string :format
      t.text :description
      t.decimal :sale_price
      t.decimal :rental_price

      t.timestamps
    end
  end
end
like image 489
Antarr Byrd Avatar asked Dec 03 '13 17:12

Antarr Byrd


3 Answers

You should not use the type keyword as the column name because it is a reserved word for ActiveRecord.


But if you really want to use it, for any reason (like if you don't have control on the DB structure), here is what you should do:

First, make sure your Movie model inherits from the (false-)"abstract" model Product:

class Product < ActiveRecord::Base
  TYPES = %w( Movie )
  before_save :set_type
  validates :type, presence: true, :inclusion => { :in => TYPES }

  def set_type
    raiser "You must override this method in each model inheriting from Product!"
  end

  # ...

class Movie < Product

  def set_type # If you don't implement this method, an error will be raised
    self.type = 'Movie'
  end

And then in your ProductsController you can manage (CRUD) all kind of products.


To add a new type of product: you just have to define a new Model inheriting from Product, implement it's set_type method and add the type in the product's Constant:

class Book < Product
  def set_type
    self.type = 'Book'
  end
  #...

class Product < ActiveRecord::Base
  TYPES = %w( Movie Book )
like image 159
MrYoshiji Avatar answered Nov 05 '22 08:11

MrYoshiji


If you don't intend to create a model for your value for 'type', then what is likely happening is 'type' is a reserved word in ActiveRecord.

See http://en.wikibooks.org/wiki/Ruby_on_Rails/ActiveRecord/Naming

"type - This is only used when you have single table inheritance and must contain a class name"

like image 23
h4xnoodle Avatar answered Nov 05 '22 07:11

h4xnoodle


Add self.inheritance_column = nil to your model. type is reserved.

like image 31
DDDD Avatar answered Nov 05 '22 07:11

DDDD