Reputation: 26071
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?
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
Upvotes: 36
Views: 34558
Reputation: 889
Another way is to name the column differently (product_type
would be fine here), and add an attribute alias alias_attribute :type, :product_type
in your model definition.
That way you can use @product.type
safely, because Rails will substitute product_type
when you read from or write to the type
attribute.
Tested with Rails 4.1.2.
Upvotes: 1
Reputation: 54882
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 )
Upvotes: 101
Reputation: 1128
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"
Upvotes: 32