I plan to use STI in Rails with the following models:
class Promo < ActiveRecord::Base
end
class Event < Promo
end
class Discount < Promo
end
There are just a couple of differences in terms of attributes between Event
and Discount
so I figure STI is a good way to go.
I'm not sure how to ensure that, for example, only Event
has an additional image_filename
attribute. I understand that it will be in the promos
table, and that it needs to be NULL
-able in case I insert a Discount
row. How do I ensure that a Discount
object knows nothing about the image_filename
attribute (i.e. is not listed in Discount.column_names
and/or can't set it) and that Event
knows about it?
I think that the concept is different, while your Promo
class inherit from ActiveRecord::Base
then all child classes inherit its attributes, so, the column names are shared in all the STI. but you still can set the column image_filename
as null in the DB and validate it in your models, so you will be able to store and update the record based in your case with something like this:
class Promo < ActiveRecord::Base
#Common validations
validates :name, presence: true
validates :user, presence: true
end
class Event < Promo
#event related validations
validates image_filename, presence: true
end
class Discount < Promo
#discount related validations
validates percentage, presence: true
end
Here is a great tutorial http://samurails.com/tutorial/single-table-inheritance-with-rails-4-part-1/
Having STI setup means you'll have 2 different forms for each child Class. That means you'll have fields available in the form accordingly for Event
and for Discount
, so when you'll save a Discount
record the second image_file field will have a nil
value by default (if you didn't changed it to something else).
Now, all attributes of your Promo
class are actually methods that you can override, so if in Discount
you'll do:
def additional_image_filename #name of the attribute
nil
end
it will always return nil as result no matter what it was saved there. An example in console based on my app where I override the name
attribute (not that I need, just showing):
2.1.5 :028 > Recipe.last
Recipe Load (0.2ms) SELECT "recipes".* FROM "recipes" ORDER BY "recipes"."id" DESC LIMIT 1
=> #<Recipe id: 4, name: "Potatoes Au Gratin", instructions: nil, created_at: "2014-12-04 12:54:26", updated_at: "2014-12-04 12:54:26">
2.1.5 :029 > Recipe.last.name
Recipe Load (0.4ms) SELECT "recipes".* FROM "recipes" ORDER BY "recipes"."id" DESC LIMIT 1
=> nil
as you can see there is a name in database and it has a value, but it returns nil
cause it was overridden.
Also you could add validations for separate Classes or callbacks that will make sure to clean up the attributes you don't need like the so called additional_image_filename
, but I don't see why you'd need this.. cause for each form you'll have separate controllers and actions I guess and therefore there will be different permitted_params
that will let you choose what fields should allowed to be saved only.
In short:
additional_image_filename
in form for Discountadditional_image_filename
in peritted_params
in controller action for DiscountDiscount
class as described above.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With