我打算在Rails中使用STI,并使用以下模型:
class Promo < ActiveRecord::Base
end
class Event < Promo
end
class Discount < Promo
end
Event
和Discount
之间的属性只有一些差异所以我认为STI是一个很好的方法。
我不确定如何确保,例如仅 Event
具有额外的image_filename
属性。我知道它会在promos
表格中,并且需要NULL
- 如果我插入Discount
行的话。 如何确保Discount
对象对image_filename
属性一无所知(即未在Discount.column_names
中列出和/或无法设置它)并且Event
知道它吗?
答案 0 :(得分:4)
我认为概念不同,而您的Promo
类继承自ActiveRecord::Base
,所有子类都继承其属性,因此,列名在所有STI中共享。但您仍然可以在数据库中将列image_filename
设置为null并在模型中对其进行验证,这样您就可以根据具体情况存储和更新记录:
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
这是一个很棒的教程http://samurails.com/tutorial/single-table-inheritance-with-rails-4-part-1/
答案 1 :(得分:1)
进行STI设置意味着您将为每个子类提供2种不同的表单。这意味着您将在表单中为Event
和Discount
提供相应的字段,因此当您保存Discount
记录时,第二个image_file字段将具有nil
默认值(如果您没有将其更改为其他内容)。
现在,Promo
类的所有属性实际上都是您可以覆盖的方法,因此如果在Discount
中您将执行此操作:
def additional_image_filename #name of the attribute
nil
end
无论在那里保存什么,它总是会返回nil。基于我的应用程序的控制台中的示例,我覆盖了name
属性(不是我需要的,只是显示):
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
正如您所看到的,数据库中有一个名称,它有一个值,但它会返回nil
,因为它被覆盖了。
此外,您可以为单独的类或回调添加验证,以确保清除您不需要的属性,如所谓的additional_image_filename
,但我不明白为什么您需要这个。 。对于每个表单,我猜你会有单独的控制器和操作,因此会有不同的permitted_params
,可以让你选择只允许保存哪些字段。
简而言之:
additional_image_filename
以获取折扣additional_image_filename
中包含“折扣”的控制器操作peritted_params
类中的方法,如上所述。