robin.curry-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
2007-Apr-25 03:51 UTC
Rails Account Plan Model Best Practices
I''m working on a rails application that will allow customers to sign up for an account with a particular plan (i.e. Free, Basic, Premium, etc) that defines what features are available, etc. Pretty standard stuff you see everywhere, however, not something I''ve implemented before. I''m struggling with trying to figure out "the rails way" - if there is one. Are there best practices you guys typically follow when implementing something like this. Don''t want to reinvent the wheel here. The direction I''ve started down is something like this: class Account < ActiveRecord::Base belongs_to :subscription_plan delegate :limit, :to => :subscription_plan delegate :feature_allowed, :to => :subscription_plan end # Table name: subscription_plans # # id :integer not null, primary key # plan_name :string(255) # limit :integer # feature_allowed :boolean class SubscriptionPlan < ActiveRecord::Base has_many :accounts end But I''m not sure if making the SubscriptionPlan an active record class and defining all the plans in the database is the best way to go, or whether it makes more sense to create something like FreeSubscriptionPlan, BasicSubscriptionPlan, PremiumSubscriptionPlan, etc as just regular classes. Anybody with thoughts on this or a pointer to some good resources? --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
> I''m working on a rails application that will allow customers to sign > up for an account with a particular plan (i.e. Free, Basic, Premium, > etc) that defines what features are available, etc. Pretty standard > stuff you see everywhere, however, not something I''ve implemented > before. > > I''m struggling with trying to figure out "the rails way" - if there is > one. Are there best practices you guys typically follow when > implementing something like this. Don''t want to reinvent the wheel > here. > > The direction I''ve started down is something like this: > > class Account < ActiveRecord::Base > belongs_to :subscription_plan > delegate :limit, :to => :subscription_plan > delegate :feature_allowed, :to => :subscription_plan > > end > > # Table name: subscription_plans > # > # id :integer not null, primary key > # plan_name :string(255) > # limit :integer > # feature_allowed :boolean > class SubscriptionPlan < ActiveRecord::Base > has_many :accounts > end > > But I''m not sure if making the SubscriptionPlan an active record class > and defining all the plans in the database is the best way to go, or > whether it makes more sense to create something like > FreeSubscriptionPlan, BasicSubscriptionPlan, PremiumSubscriptionPlan, > etc as just regular classes. > > Anybody with thoughts on this or a pointer to some good resources?Robin, You can always define a plan structure as a quick hash in environment.rb instead of using heavy duty AR classes: PLANS = { :free => { :cents => 0, :name => ''Free'', :max_pics => 10 }, :basic => { :cents => 2900, :name => ''Basic'', :max_pics => 500 }, :plus => { :cents => 4900, :name => ''Plus'', :max_pics => 1000 }, :premium => { :cents => 9900, :name => ''Premium'', :max_pics => 5000 } } Then you can use the hash to lookup names based on cents and so forth... I would recommend allowing accounts be able to have multiple subscriptions: class Account < AR has_many :subscriptions has_one :current_subscription, { :class_name => ''Subscription'', :order => ''id desc'' } end This way you can track subscription history. Hope this helps, -- Zack Chandler http://depixelate.com --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
robin.curry-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
2007-Apr-25 14:36 UTC
Re: Rails Account Plan Model Best Practices
Thanks Zack, that''s helpful. I hadn''t thought of just using a hash. So, I assume that in your example, Subscription is still an AR class, with an attribute for which plan the account selected? On Apr 24, 11:11 pm, "Zack Chandler" <zackchand...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> > I''m working on a rails application that will allow customers to sign > > up for an account with a particular plan (i.e. Free, Basic, Premium, > > etc) that defines what features are available, etc. Pretty standard > > stuff you see everywhere, however, not something I''ve implemented > > before. > > > I''m struggling with trying to figure out "the rails way" - if there is > > one. Are there best practices you guys typically follow when > > implementing something like this. Don''t want to reinvent the wheel > > here. > > > The direction I''ve started down is something like this: > > > class Account < ActiveRecord::Base > > belongs_to :subscription_plan > > delegate :limit, :to => :subscription_plan > > delegate :feature_allowed, :to => :subscription_plan > > > end > > > # Table name: subscription_plans > > # > > # id :integer not null, primary key > > # plan_name :string(255) > > # limit :integer > > # feature_allowed :boolean > > class SubscriptionPlan < ActiveRecord::Base > > has_many :accounts > > end > > > But I''m not sure if making the SubscriptionPlan an active record class > > and defining all the plans in the database is the best way to go, or > > whether it makes more sense to create something like > > FreeSubscriptionPlan, BasicSubscriptionPlan, PremiumSubscriptionPlan, > > etc as just regular classes. > > > Anybody with thoughts on this or a pointer to some good resources? > > Robin, > > You can always define a plan structure as a quick hash in > environment.rb instead of using heavy duty AR classes: > > PLANS = { > :free => { :cents => 0, :name => ''Free'', :max_pics => 10 }, > :basic => { :cents => 2900, :name => ''Basic'', :max_pics => 500 }, > :plus => { :cents => 4900, :name => ''Plus'', :max_pics => 1000 }, > :premium => { :cents => 9900, :name => ''Premium'', :max_pics => 5000 } > } > > Then you can use the hash to lookup names based on cents and so forth... > > I would recommend allowing accounts be able to have multiple subscriptions: > > class Account < AR > has_many :subscriptions > has_one :current_subscription, { :class_name => ''Subscription'', > :order => ''id desc'' } > end > > This way you can track subscription history. > > Hope this helps, > > -- > Zack Chandlerhttp://depixelate.com--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On 4/25/07, robin.curry-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org <robin.curry-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> > Thanks Zack, that''s helpful. I hadn''t thought of just using a hash. > So, I assume that in your example, Subscription is still an AR class, > with an attribute for which plan the account selected?Yes, Subscription is an AR class representing a subscription of the customer, either past or present. So if a customer changed plans five times during the year they would have 5+1 (original) subscriptions. That''s why it''s a has_many relationship. To keep it simple you can just map the Subscription cents attribute to the PLAN hash. -- Zack Chandler http://depixelate.com> On Apr 24, 11:11 pm, "Zack Chandler" <zackchand...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > > I''m working on a rails application that will allow customers to sign > > > up for an account with a particular plan (i.e. Free, Basic, Premium, > > > etc) that defines what features are available, etc. Pretty standard > > > stuff you see everywhere, however, not something I''ve implemented > > > before. > > > > > I''m struggling with trying to figure out "the rails way" - if there is > > > one. Are there best practices you guys typically follow when > > > implementing something like this. Don''t want to reinvent the wheel > > > here. > > > > > The direction I''ve started down is something like this: > > > > > class Account < ActiveRecord::Base > > > belongs_to :subscription_plan > > > delegate :limit, :to => :subscription_plan > > > delegate :feature_allowed, :to => :subscription_plan > > > > > end > > > > > # Table name: subscription_plans > > > # > > > # id :integer not null, primary key > > > # plan_name :string(255) > > > # limit :integer > > > # feature_allowed :boolean > > > class SubscriptionPlan < ActiveRecord::Base > > > has_many :accounts > > > end > > > > > But I''m not sure if making the SubscriptionPlan an active record class > > > and defining all the plans in the database is the best way to go, or > > > whether it makes more sense to create something like > > > FreeSubscriptionPlan, BasicSubscriptionPlan, PremiumSubscriptionPlan, > > > etc as just regular classes. > > > > > Anybody with thoughts on this or a pointer to some good resources? > > > > Robin, > > > > You can always define a plan structure as a quick hash in > > environment.rb instead of using heavy duty AR classes: > > > > PLANS = { > > :free => { :cents => 0, :name => ''Free'', :max_pics => 10 }, > > :basic => { :cents => 2900, :name => ''Basic'', :max_pics => 500 }, > > :plus => { :cents => 4900, :name => ''Plus'', :max_pics => 1000 }, > > :premium => { :cents => 9900, :name => ''Premium'', :max_pics => 5000 } > > } > > > > Then you can use the hash to lookup names based on cents and so forth... > > > > I would recommend allowing accounts be able to have multiple subscriptions: > > > > class Account < AR > > has_many :subscriptions > > has_one :current_subscription, { :class_name => ''Subscription'', > > :order => ''id desc'' } > > end > > > > This way you can track subscription history. > > > > Hope this helps, > > > > -- > > Zack Chandlerhttp://depixelate.com > > > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
robin.curry-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
2007-Apr-25 21:07 UTC
Re: Rails Account Plan Model Best Practices
Cool, thanks Zack. On Apr 25, 1:40 pm, "Zack Chandler" <zackchand...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> On 4/25/07, robin.cu...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org <robin.cu...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > > > > Thanks Zack, that''s helpful. I hadn''t thought of just using a hash. > > So, I assume that in your example, Subscription is still an AR class, > > with an attribute for which plan the account selected? > > Yes, Subscription is an AR class representing a subscription of the > customer, either past or present. So if a customer changed plans five > times during the year they would have 5+1 (original) subscriptions. > That''s why it''s a has_many relationship. > > To keep it simple you can just map the Subscription cents attribute to > the PLAN hash. > > -- > Zack Chandlerhttp://depixelate.com > > > On Apr 24, 11:11 pm, "Zack Chandler" <zackchand...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > > > I''m working on a rails application that will allow customers to sign > > > > up for an account with a particular plan (i.e. Free, Basic, Premium, > > > > etc) that defines what features are available, etc. Pretty standard > > > > stuff you see everywhere, however, not something I''ve implemented > > > > before. > > > > > I''m struggling with trying to figure out "the rails way" - if there is > > > > one. Are there best practices you guys typically follow when > > > > implementing something like this. Don''t want to reinvent the wheel > > > > here. > > > > > The direction I''ve started down is something like this: > > > > > class Account < ActiveRecord::Base > > > > belongs_to :subscription_plan > > > > delegate :limit, :to => :subscription_plan > > > > delegate :feature_allowed, :to => :subscription_plan > > > > > end > > > > > # Table name: subscription_plans > > > > # > > > > # id :integer not null, primary key > > > > # plan_name :string(255) > > > > # limit :integer > > > > # feature_allowed :boolean > > > > class SubscriptionPlan < ActiveRecord::Base > > > > has_many :accounts > > > > end > > > > > But I''m not sure if making the SubscriptionPlan an active record class > > > > and defining all the plans in the database is the best way to go, or > > > > whether it makes more sense to create something like > > > > FreeSubscriptionPlan, BasicSubscriptionPlan, PremiumSubscriptionPlan, > > > > etc as just regular classes. > > > > > Anybody with thoughts on this or a pointer to some good resources? > > > > Robin, > > > > You can always define a plan structure as a quick hash in > > > environment.rb instead of using heavy duty AR classes: > > > > PLANS = { > > > :free => { :cents => 0, :name => ''Free'', :max_pics => 10 }, > > > :basic => { :cents => 2900, :name => ''Basic'', :max_pics => 500 }, > > > :plus => { :cents => 4900, :name => ''Plus'', :max_pics => 1000 }, > > > :premium => { :cents => 9900, :name => ''Premium'', :max_pics => 5000 } > > > } > > > > Then you can use the hash to lookup names based on cents and so forth... > > > > I would recommend allowing accounts be able to have multiple subscriptions: > > > > class Account < AR > > > has_many :subscriptions > > > has_one :current_subscription, { :class_name => ''Subscription'', > > > :order => ''id desc'' } > > > end > > > > This way you can track subscription history. > > > > Hope this helps, > > > > -- > > > Zack Chandlerhttp://depixelate.com--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Not to step on anyones toes, but I would recommend against defining a PLAN hash in environment.rb. In doing so, a constant is essentially being used as a global variable. A better idea would be to encapsulate such data into your domain model appropriately. Not knowing exactly what that is, I''d suggest an easy start is something similar to the following (a few things removed for brevity): class Account < ActiveRecord::Base class_inheritable_accessor :plan_types self.plan_types = { :free => { :cents => 0, :name => ''Free'', :max_pics => 10 }, :basic => { :cents => 2900, :name => ''Basic'', :max_pics => 500 }, :plus => { :cents => 4900, :name => ''Plus'', :max_pics => 1000 }, :premium => { :cents => 9900, :name => ''Premium'', :max_pics => 5000 } } end Furthermore, you could also define your own non-AR-based Plan model that reads the above data from a YAML file rather than having it in your code, and so forth. I would suggest you investigate that approach, personally, if you feel just using an AR model for the plan data isn''t appropriate. - Gabriel On 4/25/07, robin.curry-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org <robin.curry-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> > Cool, thanks Zack. > > On Apr 25, 1:40 pm, "Zack Chandler" <zackchand...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > On 4/25/07, robin.cu...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org <robin.cu...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > > > > > > > > Thanks Zack, that''s helpful. I hadn''t thought of just using a hash. > > > So, I assume that in your example, Subscription is still an AR class, > > > with an attribute for which plan the account selected? > > > > Yes, Subscription is an AR class representing a subscription of the > > customer, either past or present. So if a customer changed plans five > > times during the year they would have 5+1 (original) subscriptions. > > That''s why it''s a has_many relationship. > > > > To keep it simple you can just map the Subscription cents attribute to > > the PLAN hash. > > > > -- > > Zack Chandlerhttp://depixelate.com > > > > > On Apr 24, 11:11 pm, "Zack Chandler" <zackchand...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > > > > I''m working on a rails application that will allow customers to sign > > > > > up for an account with a particular plan (i.e. Free, Basic, Premium, > > > > > etc) that defines what features are available, etc. Pretty standard > > > > > stuff you see everywhere, however, not something I''ve implemented > > > > > before. > > > > > > > I''m struggling with trying to figure out "the rails way" - if there is > > > > > one. Are there best practices you guys typically follow when > > > > > implementing something like this. Don''t want to reinvent the wheel > > > > > here. > > > > > > > The direction I''ve started down is something like this: > > > > > > > class Account < ActiveRecord::Base > > > > > belongs_to :subscription_plan > > > > > delegate :limit, :to => :subscription_plan > > > > > delegate :feature_allowed, :to => :subscription_plan > > > > > > > end > > > > > > > # Table name: subscription_plans > > > > > # > > > > > # id :integer not null, primary key > > > > > # plan_name :string(255) > > > > > # limit :integer > > > > > # feature_allowed :boolean > > > > > class SubscriptionPlan < ActiveRecord::Base > > > > > has_many :accounts > > > > > end > > > > > > > But I''m not sure if making the SubscriptionPlan an active record class > > > > > and defining all the plans in the database is the best way to go, or > > > > > whether it makes more sense to create something like > > > > > FreeSubscriptionPlan, BasicSubscriptionPlan, PremiumSubscriptionPlan, > > > > > etc as just regular classes. > > > > > > > Anybody with thoughts on this or a pointer to some good resources? > > > > > > Robin, > > > > > > You can always define a plan structure as a quick hash in > > > > environment.rb instead of using heavy duty AR classes: > > > > > > PLANS = { > > > > :free => { :cents => 0, :name => ''Free'', :max_pics => 10 }, > > > > :basic => { :cents => 2900, :name => ''Basic'', :max_pics => 500 }, > > > > :plus => { :cents => 4900, :name => ''Plus'', :max_pics => 1000 }, > > > > :premium => { :cents => 9900, :name => ''Premium'', :max_pics => 5000 } > > > > } > > > > > > Then you can use the hash to lookup names based on cents and so forth... > > > > > > I would recommend allowing accounts be able to have multiple subscriptions: > > > > > > class Account < AR > > > > has_many :subscriptions > > > > has_one :current_subscription, { :class_name => ''Subscription'', > > > > :order => ''id desc'' } > > > > end > > > > > > This way you can track subscription history. > > > > > > Hope this helps, > > > > > > -- > > > > Zack Chandlerhttp://depixelate.com > > > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
I think the answer depends on two questions: - How dynamic will the number of subscription plans be? - Who will control the plans (name, feature set, etc)? If the number of plans could vary wildly over time and an end user needs to have full control over them then the very flexible approach you''re outlining makes sense. It''s really no different than a standard role-based authorization with the ''plan'' taking the place of the role. You could allow the end user ultimate control -- allowing them to authorize controller/action for a particular plan -- and not have to worry about coding authorization to a feature. If the number of plans is more stable and the development team will be involved with the evolving plans then you could go with a static array or hash to provide the names and db values for the plans. If you don''t envision the plans containing much more than the limit and allowed flag you describe then you may not need more than that. If you expect more features to be added to the list of allowed/ disallowed for a plan you''ll need to add some kind of association between the plan and the feature(s). That is, you''re better to build a table of AllowedFeatures and using a join or has/belongs relationship to the SubscriptionPlan. The SubscriptionPlan could use a method to respond to the (delegated) ''feature_allowed'', looking up the feature through it''s collection of AllowedFeatures. On Apr 24, 11:51 pm, "robin.cu...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org" <robin.cu...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> I''m working on a rails application that will allow customers to sign > up for an account with a particular plan (i.e. Free, Basic, Premium, > etc) that defines what features are available, etc. Pretty standard > stuff you see everywhere, however, not something I''ve implemented > before. > > I''m struggling with trying to figure out "the rails way" - if there is > one. Are there best practices you guys typically follow when > implementing something like this. Don''t want to reinvent the wheel > here. > > The direction I''ve started down is something like this: > > class Account < ActiveRecord::Base > belongs_to :subscription_plan > delegate :limit, :to => :subscription_plan > delegate :feature_allowed, :to => :subscription_plan > > end > > # Table name: subscription_plans > # > # id :integer not null, primary key > # plan_name :string(255) > # limit :integer > # feature_allowed :boolean > class SubscriptionPlan < ActiveRecord::Base > has_many :accounts > end > > But I''m not sure if making the SubscriptionPlan an active record class > and defining all the plans in the database is the best way to go, or > whether it makes more sense to create something like > FreeSubscriptionPlan, BasicSubscriptionPlan, PremiumSubscriptionPlan, > etc as just regular classes. > > Anybody with thoughts on this or a pointer to some good resources?--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---