Hasmanythru? Design Query, Willing to make it worthwhile for

Hi Guys,

Looking for help on a design issue! Not looking for free help either.

So the help i need is around polymorphic associations.

I have an app where the customer’s “case” model has to be associated
with ONE rateplan.
The Rateplan model can be on many types and are predefined by the system
owners. I currently have a rake task to load up all the rateplans (later
i’ll provide an admin interface).
For modelling the Rateplan types i used Single Table Inheritance.

The case form will have a select box of rateplans to choose from.
So far…

[code=]class Case < ActiveRecord::Base
belongs_to :rateplan
end

class Rateplan < ActiveRecord::Base
has_many :cases
end

class SimpleRateplan < Rateplan
end

class FlexRateplan < Rateplan
end

class FunkyComplexRateplan < Rateplan
end[/code] (Parked at Loopia)

Now the complexity is that depending on the type of rateplan chosen
there are some fields that need to be provided by the case for e.g. if a
FlexRateplan is chosen a number of parameters can be provided by the
customer when creating the case. So, I’m having difficulty trying to
implement methods that need to work on the case. I know the relationship
between Case and Rateplan is polymorphic (depending the on the type of
rateplan picked).

Thus after design 2.0 , I came up with

[code=]class Case < ActiveRecord::Base
has_one :case_rateplan
end

class CaseRateplan < ActiveRecord::Base
belongs_to :case
belongs_to :rateplan
end

class Rateplan < ActiveRecord::Base
has_many :case_rateplans
has_many :cases , :through => :case_rateplans
end

class SimpleRateplan < Rateplan
end

class FlexRateplan < Rateplan
end

class FunkyComplexRateplan < Rateplan
end[/code] (Parked at Loopia)
and after another iteration it started looking like

[code=]class Case < ActiveRecord::Base
has_one :case_rateplan

def use_calc
# use case_rateplan.calc
end

end

class CaseRateplan < ActiveRecord::Base
belongs_to :case
end

class SimpleCaseRateplan < CaseRateplan
belongs_to :case
belongs_to :simple_rateplan

def calc
# read mostly rateplan fields
# read some case fields
end
end

class FlexCaseRateplan < CaseRateplan
belongs_to :flex_rateplan

def calc
# read some rateplan fields
# read some case fields
end
end

class FunkyComplexCaseRateplan < CaseRateplan
belongs_to :funky_complex_rateplan

def calc
# read a few rateplan fields
# read a number of case fields
end
end

class Rateplan < ActiveRecord::Base
has_many :case_rateplans
has_many :cases , :through => :case_rateplans
end

class SimpleRateplan < Rateplan
end

class FlexRateplan < Rateplan
end

class FunkyComplexRateplan < Rateplan
end[/code] (Parked at Loopia)
The association table models could access the rateplan fields as well as
the case fields. But things have started to look fubar.

Looking for design guidance.

I’m not afraid to go and read, so point me to a good reference doc or
app (i’ll read the code). I’m of course willing to shell out some money
(Paypal?) and recommend (WorkingWithRails?) if someone is kind of enough
to provide appropriate and detailed guidance.

Cheers,
Aditya

P.S.: Please don’t ask me to Google it (BTDT).
MySkillLevel: Definitely NOT a newbie; Definitely not a master!

Cheers,
Aditya

Hi,

As I understand it, depending on the level of rate plan that a user
selects, the user will need to provide different levels of
information. I would probably do as follows:

For the Case model, define every single parameter that is required so
that there is one table for your cases. From a view perspective, you
would probably need to use Javascript to present the correct inputs
depending on the plan selected.

I would then create a RatePlan model defining the varying rate plans
that you offer. I assume these all have common features.

I would then create an intermediate Subscriptions model so a Case
has_one subscription and the subscription belongs_to one RatePlan.
This would be to ensure a resource based approach to my application
e.g. create subscription, update subscription etc.

You would then end up with:

def Case < ActiveRecord::Base
has_one :subscription
has_one :rate_plan, :through => :subscription
end

def Subscription < ActiveRecord::Base
belongs_to :case
belongs_to :rate_plan
end

def RatePlan < ActiveRecord::Base
has_many :subscriptions
end

I created something similar for an app I’m working on at the moment
but don’t have access to the files at the moment. I think the
associations above are correct and hope they help.

Robin

On Feb 13, 11:23 am, Aditya S. [email protected]

Robin F. wrote:

Hi,

As I understand it, depending on the level of rate plan that a user
selects, the user will need to provide different levels of
information. I would probably do as follows:

Totally correct. The rateplan provides certain attributes but some are
flexible, so the case form captures the bits which are flexible.

For the Case model, define every single parameter that is required so
that there is one table for your cases. From a view perspective, you
would probably need to use Javascript to present the correct inputs
depending on the plan selected.
Yup, the UI part is clear to me! But i suppose what would be nice is to
dynamically be able to identify the Rateplan “type” can render the
partial based on model’s type. So, SimpleRateplan would render
simplerateplan/_case_rp_form.html.erb and ComplexRateplan would render
complexrateplan/_case_rp_form.html.erb

Meaning the views are dynamically picked based on the inherited model.
Haven’t seen that as yet! Or dont know how as yet.

I would then create a RatePlan model defining the varying rate plans
that you offer. I assume these all have common features.
Not exactly, the rateplan “types” differ a fair bit. But not enough not
to
implement STI. I’ve got about 4 classes inheriting from Rateplan.

I would then create an intermediate Subscriptions model so a Case
has_one subscription and the subscription belongs_to one RatePlan.
This would be to ensure a resource based approach to my application
e.g. create subscription, update subscription etc.

You would then end up with:

def Case < ActiveRecord::Base
has_one :subscription
has_one :rate_plan, :through => :subscription
end
Now, has_one :through does not exist. I need to hack it in from what
i’ve been told on IRC. Someone suggested I build a plugin to support
this. There is another unverified sample code on the RailsWiki. Frankly,
I don’t understand it enough to make this change as yet. But if need be,
i’ll do it.

def Subscription < ActiveRecord::Base
belongs_to :case
belongs_to :rate_plan
end

def RatePlan < ActiveRecord::Base
has_many :subscriptions
end

My problem is that the fields that i need to do calculations on are
based on Rateplan’s type (they need to read fields from the case as well
as the rateplan). So i’ll need to do parallel subclassing/inheritance on
the Subscription as well. (Parallel to Rateplan’s subclassing). This is
getting ugly right? Probably not the best design, or is it? :slight_smile:

Thanks heaps for your help Robin. If you’ve got a favourite charity or a
paypal account, i’m happy to chip in a token amount!

Cheers,
Aditya