2

So this is more or less of what I'm trying:

I have an abstract class extracted out for all the common functionalities, Which includes a polymorphic association, so it looks like this:

class Card < ActiveRecord::Base
  self.abstract_class = true
  belongs_to :cardable, polymorphic: true
  ...
end

class Spell < Card
  ...
end

class Unit < Card
  ...
end

Now when i try to use polymorphic associations on this, something on the lines of:

  class Deck < ActiveRecord::Base
    has_many :cards, :as => :cardable
  end

  class Hand < ActiveRecord::Base
    has_many :cards, :as => :cardable
  end

The belongs_to part of things work fine, i.e. spell.cardable works perfectly as expected

However, because of the abstract class, has_many doesn't work well i.e. hand.cards or deck.cards always gives an empty ActiveRecord Association

Is this a workable model, or if not, what would be a better way to model this entire scenario?

Josh Kurien
  • 83
  • 1
  • 8
  • Why do you think you should be using abstract class here in the first place? Without more info it's hard to know WHY or what you're trying to do here so can't provide an answer. It's not best practice with models in rails. See this article https://medium.com/@jeremy_96642/deep-rails-how-to-use-abstract-classes-6aee9b686e75 – lacostenycoder Mar 09 '19 at 21:01
  • I'm not aware of the concept of an "abstract class" in Ruby. Could you please define the term? – Cary Swoveland Mar 09 '19 at 21:43
  • @lacostenycoder It is because both the child classes have very similar behaviour; however their differences in schema forces me to not use STI – Josh Kurien Mar 10 '19 at 02:43
  • 1
    @CarySwoveland Abstract classes is a concept in rails, where: if you mark a class as abstract, then it does not need a corresponding table (in newer rails versions the autogenerated `ApplicationRecord` class is an example of the same). and then you can use it as a parent class for inheritance, where each child class will need a different table. – Josh Kurien Mar 10 '19 at 02:50
  • Josh, thanks for the explanation. – Cary Swoveland Mar 10 '19 at 03:18

2 Answers2

2

You can simulate an abstract class by use initializer

class Card < ActiveRecord::Base
  def initialize 
    raise "Card cannot be instantiated directly" if self.class == Card
  end
  belongs_to :cardable, polymorphic: true
  ...
end

you maintain your STI and have pseudo-abstract class please read this comment on stackoverflow:

Sergio Belevskij
  • 1,688
  • 21
  • 21
1

@JoshKurien well it sounds like you've answered your own question "it does not need a corresponding table" but in your case aren't cards an actual table in your DB? If so, just get rid of this line as it's clearly breaking the polymorphism provided by ActiveRecord

self.abstract_class = true

Perhaps a better way is to just let each model class which has a database table be defined as a regular model. If you need shared behavior in your models, can you use model concerns and extend those models from a shared concern?

See How to use concerns in Rails 4

But there are some who think concerns are a bad design, in that case you may also want to check out https://github.com/AndyObtiva/super_module as another alternative.

lacostenycoder
  • 8,780
  • 3
  • 23
  • 38
  • nope, cards is not a table for me. In this case, there are 4 different tables: `spells`, `units`, `decks` and `hands` The abstract class use case is quite real. I know that this is breaking polymorphism. I guess my question was more on what would be a better way to model this scenario – Josh Kurien Mar 10 '19 at 09:15
  • 1
    @JoshKurien I've updated my answer with some other ideas. – lacostenycoder Mar 10 '19 at 09:37