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