Rails:派生类的未知属性错误

时间:2014-04-28 06:15:37

标签: ruby-on-rails ruby-on-rails-3

我有一个名为PaypalPayment的模型:

class PaypalPayment < PaymentMethod
  belongs_to :order
  def provider_class
    PaypalPayment
  end

  def process!
  end   
end

我为它生成了以下迁移:

class CreatePaypalPayments < ActiveRecord::Migration
  def change
    create_table :paypal_payments do |t|
      t.integer :order_id
      t.integer :payment_id

      t.timestamps
    end
  end
end

class AddDetailsToPaypalPayment < ActiveRecord::Migration
  def change
    add_column :paypal_payments, :state, :string
    add_column :paypal_payments, :amount, :decimal
    add_column :paypal_payments, :cc, :string
    add_column :paypal_payments, :cm, :string
  end
end

迁移后,表格如下所示:

development_database=# select * from paypal_payments;
 id | order_id | payment_id | created_at | updated_at | state | amount | cc | cm 

但是当我尝试初始化此模型的对象时,我得到的是unknown attribute: payment_id

@paypal_payment = PaypalPayment.new(:payment_id => params[:tx], :state => params[:st], :cc => params[:cc], :cm => params[:cm], :order_id => params[:id])

编辑: db / schema.rb:

create_table "paypal_payments", :force => true do |t| 
    t.integer "order_id" 
    t.integer "payment_id" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    t.string "state" 
    t.decimal "amount" 
    t.string "cc" 
    t.string "cm" 
end

4 个答案:

答案 0 :(得分:2)

在关系数据库中有不同的模型继承方法,Martin Fowler列出了以下选项:

  1. Single Table Inheritance:所有类都存储在一个表中
  2. Class Table Inheritance:所有课程都有自己的表格
  3. Concrete Table Inheritance:只有具体的类有一个表(例如在你的例子中PaymentMethod如果是抽象的,就没有表)
  4. 现在ActiveRecord only supports STI:单表继承。

    所以,如果你写

    class PaypalPayment < PaymentMethod
    

    ActiveRecord将假设STI并查找类型列,此外,只会查找payment_methods表。

    根据您的需求,在大多数情况下,STI是完美的。有时我更喜欢Class和Concrete Table Inheritance,但特别是对于关联,这需要更多的家庭住宅,因为:

    • e.g。您有不同的付款方式,但它们存储在不同的表格中
    • 您想一次访问所有付款方式,您需要&#34;抽象类&#34;
    • 您需要按照可能的付款方式进行关联
    • 如果您有&#34;抽象类&#34;,您如何链接到&#34;真实付款方式&#34;。一种方法是包含子名称和子项ID作为链接。

    有很多方法可以解决这个问题,但总是比使用单个表更难。这也是拉伸关系数据模型,因为根据所选择的解决方案,不会自动支持外键约束。我可以详细介绍一下 但我不确定这是否相关,因为你的例子似乎是STI的经典案例。

    如果你想使用类表继承或具体表继承,每个类必须派生自`ActiveRecord :: Base``,如果需要,你应该包含一个带有共享行为的模块(或关注点)(因为ruby确实如此)不支持多重继承)。

答案 1 :(得分:1)

我相信你必须在“PaymentMethods”表中添加“type”列。这将允许它是可继承的。没有类型列,当您实例化PaypalPayment时,它认为它是一个PaymentMethod,因此没有PaypalPayment的唯一字段。但是,当您将“type”列添加到PaymentMethod时,它将存储“PaypalPayment”,ActiveRecord知道使PaypalPayment方法可用。你应该为PaymentMethod创建一个模型,并确保它继承ActiveRecord :: Base

def change
  add_column :payment_methods, :type, :string
end

以下是一些信息: http://www.archonsystems.com/devblog/2011/12/20/rails-single-table-inheritance-with-polymorphic-association/

答案 2 :(得分:0)

我会这样做:

检查您的Rails控制台 -

$ rails c
$ payment = PaypalPayment.find(1)
$ payment.column_names #-> should reveal which columns Rails comes back with

检查Rails正在拾取属性

为了测试,请尝试attr_accessor :payment_id查看是否有效。您可能没有在模型中允许该属性

在Rails4中,这意味着使用strong params,但在Rails 3中,我认为这意味着使用attr_accessible这样:

#app/models/paypal_payment.rb
Class PaypalPayment < ActiveRecord::Base
    attr_accessible :payment_id #-> tests parameter passing
    attr_accessor :payment_id #-> tests virtual attribute assignment
end

答案 3 :(得分:0)

我知道我这里的节目有点迟了,但是如果有人遇到类似Rails 5.1的问题,在我的情况下,我能够通过在我的父类中包含以下行来解决问题

self.abstract_class = true