web-dev-qa-db-fra.com

Type d'héritage à une seule table non valide: Rails

Je reçois cette erreur en essayant de créer un nouveau produit dans mon application Rails. 

Type d'héritage à une seule table non valide: Movie n'est pas une sous-classe de Produit

Comment puis-je résoudre ça?

enter image description here

manette

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
29
Antarr Byrd

Vous ne devez pas utiliser le mot clé typecomme nom de colonne car il s'agit d'un mot réservé pour ActiveRecord .


Mais si vous voulez vraiment l'utiliser, pour quelque raison que ce soit (comme si vous n'avez pas le contrôle sur la structure de la base de données), voici ce que vous devriez faire:

Tout d’abord, assurez-vous que votre modèle Movie hérite du modèle (abstrait) "abstrait".

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

Ensuite, dans votre ProductsController, vous pouvez gérer (CRUD) tout type de produit.


Pour ajouter un nouveau type de produit: , il vous suffit de définir un nouveau modèle héritant du produit, de mettre en œuvre sa méthode set_type et d'ajouter le type dans la constante du produit:

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

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

Si vous n'avez pas l'intention de créer un modèle correspondant à votre valeur pour "type", il est probable que "type" correspond à un mot réservé dans ActiveRecord.

Voir http://fr.wikibooks.org/wiki/Ruby_on_Rails/ActiveRecord/Naming

"type - Ceci n'est utilisé que lorsque vous avez l'héritage d'une table et que vous devez contenir un nom de classe"

27
h4xnoodle

Ajoutez self.inheritance_column = nil à votre modèle. le type est réservé.

19
DDDD

Une autre méthode consiste à nommer la colonne différemment (product_type conviendrait ici) et à ajouter un alias d'attribut alias_attribute :type, :product_type dans la définition de votre modèle.

De cette façon, vous pouvez utiliser @product.type en toute sécurité, car Rails substituera product_type lors de la lecture ou de l'écriture dans l'attribut type.

Testé avec Rails 4.1.2.

0
Goulven