Specify unique attributes for child models on rails using STI

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 only a few differences in attributes between Event and Discount , so I think STI is a good way to go.

I am not sure how to make sure, for example, that only Event has an additional attribute image_filename . I understand that it will be in the promos table and that it should be NULL -able if I insert the line Discount . How to ensure that the Discount object does not know anything about the image_filename attribute (i.e. is not specified in Discount.column_names and / or cannot set it) and what does the Event know about this?

+5
source share
2 answers

I think the concept is different, and your Promo class inherits from ActiveRecord::Base , then all child classes inherit its attributes, so the column names are shared in all STIs. but you can still set the image_filename column to null in the database and check it in your models so that you can store and update a record based on your case, 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/

+4
source

After installing STI, you will have 2 different forms for each child class. This means that you will have fields in the form for Event and Discount , respectively, so when you save the Discount record, the second image_file field will have a nil value by default (if you didn’t change it to something else).

Now all the attributes of your Promo class are actually methods that you can override, so if in Discount you do:

 def additional_image_filename #name of the attribute nil end 

it will always return nil as a result no matter what was stored there. An example in the console based on my application where I override the name attribute (not the one I need, it just shows up):

 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 the database and it matters, but returns nil because it was overridden.

You can also add checks for individual classes or callbacks that will clear attributes that you do not need, for example, the so-called additional_image_filename , but I don’t understand why you need it. for each form you will have separate controllers and actions that I assume, and therefore there will be different permitted_params that allow you to choose which fields should only be saved.

In short:

  • Do not include additional_image_filename in the discount form
  • Do not include additional_image_filename in peritted_params in controller action for discount
  • Set the value as nil in db or override the method in the Discount class as described above.
+1
source

Source: https://habr.com/ru/post/1208821/


All Articles