Model question

I'm pondering a way of representing a scenario without too much
fiddling with the database. I'm 90% happy with it, but have one
problem (where I probably just don't know the right AR approach to
use).

I have a "people" table, from which records are displayed depending on
whether they are new leads, exisiting customers, or just contacts
(maybe reps at stores). I'm keeping them in one DB table, but I don't
want to use STI, as a single person *might* be more than one "type".

Here's the reasoning:

A Person can be flagged as "new lead".
A Person can have Orders (which makes them a customer).
A NewLead can have Orders - for instance trial packs that their sales
person has sent them - which makes them a customer as well as a lead.
A Person record can exist, and be neither a Customer or NewLead (I'm
calling these guys "contacts" for now, but they might as easily be
Foos or Bars...)

I want to be able to access the records using named_scopes, as, of
course, I want to be able to chain other scopes - so named_scopes are
essential (so I can get all the NewLeads for a given sales person, or
all the Contacts with a given surname, etc)

So I've got this structure:

class Person < ActiveRecord::Base
  # ...Person stuff
end

class NewLead < Person
  default_scope :conditions => "people.new_lead = 1" # ... simple
condition to return only new leads
end

class Customer < Person
  default_scope :group => "people.id", :joins => :orders # ...
returns me unique instances (thanks to the :group) of just those
people who have any order records
end

class Contact < Person
  #... my problem... what does my default scope need to be to return
me people *without* orders, and with the "new_lead" flag set to zero?
end

The logic for NewLead and Customer is working perfectly - if I have a
Person with id=123 who has no orders, but new_lead set to "1", calling
"NewLead.find(123)" gives me a valid NewLead record, but
"Customer.find(123)" gives me a "record not found error" - just what I
want to happen. Then if that person has an order placed for them, both
of the finds returns a valid record.

But how to return records with no Orders.... ? I'm thinking that I may
need something along the lines of:

  default_scope :conditions => "people.id not in (select distinct
people.id from people joins orders on orders.person_id = people.id)
and people.new_lead = 0"

But that seems ugly.

Any suggestions for neater ways?

But how to return records with no Orders… ? I’m thinking that I may

need something along the lines of:
But that seems ugly.

Any suggestions for neater ways?

How about using counter caches - something like:

class Order < ActiveRecord::Base

belongs_to :customer, :counter_cache => true

end

class Customer < Person

has_many :orders

default_scope :conditions => { :orders_count > 0}

end

http://guides.rails.info/association_basics.html#belongs-to-association-reference

(section 4.1.2.4)

Cheers,

Andy

Nice idea... that would do well, and clean it up a bit - I just tried
my approach (after fixing typos...) and it works, but just smells...
:slight_smile:

Thanks for that.