How to structure this so I get all the benefits from STI with none of the consequences? (Pretty irresponsible, I know.)

僤鯓⒐⒋嵵緔 提交于 2020-01-04 06:27:29

问题


Say I have the following example of associations in a Rails app:

I'm considering combining the *Posting models under STI. One problem with STI is the potential for many attributes that are only related to one subclass (i.e., a lot of denormalized nil values). This is especially worrisome when your subclasses and going to evolve and grow in the future. I've read a few related posts (such as this), however, as you can see in my example, the potential subclass-specific fields will not necessarily be just attributes, but rather, a lot of belongs_to associations.

My question is, how could I restructure this to use STI from a Posting model for all the common attributes/methods (of which there will be quite a few in my actual app), but keep the unique subclass-specific attributes and belongs_to associations from piling up in the Posting model? Also, the ability to access @board.postings and work with those standard methods is important.

For example, I've thought about moving the type-specific attributes to another model:

class CarPosting < Posting
  has_one: car_posting_detail
end

class CarPostingDetail < ActiveRecord::Base
  belongs_to :car_posting
  belongs_to :car_make
  belongs_to :car_model
end

Although, this starts to create a lot of joins, I'm not sure I have the has_one/belongs_to declarations in the right direction, and you have to start chaining calls (e.g., @posting.car_posting_detail.car_make).

Are there other design patterns you have seen for accomplishing this?


回答1:


You could use polymorphic associations for this.

Post model belongs_to :postable, :polymorphic => true

car, event and all the other "postable" classes would have this relationship

has_many :posts, as: :postable 

Post would hold the postable_id and postable_type

More info here http://guides.rubyonrails.org/association_basics.html#polymorphic-associations




回答2:


You basically have to 2 options for accomplishing inheritance.

First, you can use rails STI as you suggested. The downside is that end up with nil attribute for the child classes that do not use all of the fields. Your idea to reduce this by adding type-specific attributes to another model is a great way to reduce this. However, you should keep the implementation as DRY as possible by defining a has_one :detail for the Posting. Then you can simply assign specific detail types in the Posting childs. For example, CarPosting's detail would be CarPostingDetail. This is convenient because then all Posting children will have their details accessed identically, but will still have different details. So the query now looks like @posting.detail.car_make. To take this one step further, you can define a custom helper method in your Posting model to grab each attribute in the current Posting's detail and create an accessor for it. Now the entire detail layer is transparent and you can simply access those attributes by saying @posting.car_make.

Second, you can use an abstract class. This is essentially the reverse of STI. You create an abstract model class which can never be instantiated. Thus, you cannot define any relationships in the Posting class because it has no table. Each child of the abstract Posting class has its own separate table. The main advantage of doing this would be the ability to define methods for all of your Posting types without copy and pasting them into every model. So this options is better if there are some overlapping functionality across the models, but very little data overlap.



来源:https://stackoverflow.com/questions/22161468/how-to-structure-this-so-i-get-all-the-benefits-from-sti-with-none-of-the-conseq

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!