Reputation: 7280
I have a model named PaypalPayment
:
class PaypalPayment < PaymentMethod
belongs_to :order
def provider_class
PaypalPayment
end
def process!
end
end
I generated the following migrations for it:
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
and
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
After the migration the table looks something like:
development_database=# select * from paypal_payments;
id | order_id | payment_id | created_at | updated_at | state | amount | cc | cm
But when I try to initialize an object of this model, I'm getting the 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])
EDIT: 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
Upvotes: 4
Views: 1946
Reputation: 403
I know I'm a bit late the show here, but if anyone is encountering a similar problem with Rails 5.1, in my case I was able to resolve the issue by including the following line in my parent classes
self.abstract_class = true
Upvotes: 0
Reputation: 50057
There are different ways to model inheritance in a relational database, Martin Fowler lists the following options:
PaymentMethod
if being abstract, would not have a table)Now ActiveRecord only supports STI: single table inheritance.
So if you write
class PaypalPayment < PaymentMethod
ActiveRecord will assume STI and look for a type column, and furthermore, will only look for payment_methods
table.
Depending on what you want, in most cases, STI is just perfect. Sometimes I prefer the Class and Concrete Table Inheritance better, but especially for associations this needs a little more householding, since:
There are lots of way to solve this, but always harder than using a single table. Also this is stretching the relational datamodel, as depending on the chosen solution, foreign key constraints are not automatically supported. I could go into detail, but I am not sure if this is relevant, as your example seems a classic case for STI.
If you do want to use Class Table Inheritance or Concrete Table Inheritance, each class has to derive from `ActiveRecord::Base`` and you should include a module (or concern) with the shared behaviour if needed (since ruby does not support multiple inheritance).
Upvotes: 3
Reputation: 705
I believe you have to add the column "type" to your PaymentMethods table. This will allow it to be inheritable. Without the type column, when you instantiate a PaypalPayment, it thinks it's a PaymentMethod and hence has none of the unique fields of PaypalPayment. However when you add the column "type" to PaymentMethod, then it will store "PaypalPayment" and ActiveRecord knows to make the PaypalPayment methods available. You should probably make a model for PaymentMethod also and make sure it inherits ActiveRecord::Base
def change
add_column :payment_methods, :type, :string
end
Here's some info: http://www.archonsystems.com/devblog/2011/12/20/rails-single-table-inheritance-with-polymorphic-association/
Upvotes: 1
Reputation: 76774
I'd do this:
Check your Rails Console --
$ rails c
$ payment = PaypalPayment.find(1)
$ payment.column_names #-> should reveal which columns Rails comes back with
Check Rails is picking up the attribute
For testing's sake, just try attr_accessor :payment_id
to see if that works. You might not have permitted the attribute in your model
In Rails4, that means using strong params
, but in Rails 3, I think it means using attr_accessible
like this:
#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
Upvotes: 0