Ruby-on-rails 无效的单表继承类型:Rails

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20357997/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 23:05:33  来源:igfitidea点击:

Invalid single-table inheritance type: Rails

ruby-on-railsinheritanceruby-on-rails-4

提问by Antarr Byrd

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

尝试在我的 Rails 应用程序中创建新产品时出现此错误。

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

单表继承类型无效:Movie 不是 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

回答by MrYoshiji

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

不应使用type关键字作为列名,因为它是 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:

首先,确保您的 Movie 模型继承自 (false-)"abstract" 模型 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.

然后在您的 ProductsController 中,您可以管理(CRUD)所有类型的产品。



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:

要添加新类型的产品:您只需要定义一个从 Product 继承的新模型,实现它的 set_type 方法并将类型添加到产品的常量中:

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

class Product < ActiveRecord::Base
  TYPES = %w( Movie Book )

回答by h4xnoodle

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.

如果您不打算为“类型”的值创建模型,那么可能发生的情况是“类型”是 ActiveRecord 中的保留字。

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

请参阅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"

type- 这仅在您具有单表继承且必须包含类名时使用”

回答by DDDD

Add self.inheritance_column = nilto your model. type is reserved.

添加self.inheritance_column = nil到您的模型中。类型被保留。

回答by Goulven

Another way is to name the column differently (product_typewould be fine here), and add an attribute alias alias_attribute :type, :product_typein your model definition.

另一种方法是以不同的方式命名列(product_type在这里很好),并alias_attribute :type, :product_type在模型定义中添加属性别名。

That way you can use @product.typesafely, because Rails will substitute product_typewhen you read from or write to the typeattribute.

这样您就可以@product.type安全地使用,因为 Rails 会product_type在您读取或写入type属性时进行替换。

Tested with Rails 4.1.2.

使用 Rails 4.1.2 测试。