The simplified example is that I have several classes inheriting from an Asset
class, which is an ActiveRecord
model. When I use create
or create!
on one of the subclasses both the db layer and ActiveRecord layer validations for one field are ignored.
The Asset table has a type
field with null: false
, the Asset model has validates_presence_of :type
and also has attribute :type, default: self.name
.
If I use new
on a subclass, such as Item, it behaves as expected, I get an Item
with the type
field set to "Item"
. If I use create
or create!
with valid attributes, the defaults are not applied, validation is ignored and I get a persisted record with a type
field of nil
.
What's odd is that other validations are respected. If I try creating a new Item without a name
attribute, validates_presence_of :name
properly raises a validation error.
Here's some pared down code snippets for reference:
class CreateAssets < ActiveRecord::Migration[6.0]
def change
create_table :assets do |t|
t.string :type, null: false
t.string :name
# ...
end
end
end
class Asset < ApplicationRecord
enum type: {
Item: :Item,
Accessory: :Accessory,
Component: :Component,
Consumable: :Consumable,
}
attribute :type, default: self.name
validates_presence_of :name
validates_presence_of :type
end
class Item < Asset
# ...
end
i = Item.create({ ... })
i.type
#nil
i.persisted?
#true
i.valid?
#false
i = Item.new({ ... })
i.type
#"Item"
i.valid?
#true
CodePudding user response:
'type' is a reserved column name in ActiveRecord because it is used to indicate Single Table Inheritance (STI) . If you are not intending to use STI you should pick a different column name otherwise the STI behaviors will interfere with what you're trying to do here.