Use Polymorph or STI or.

Im creating an expense report.

I don't know if Im on the right path but heres what im thinking...
When submitting an expense report the user could have travel expenses,
parking expenses, cell phone expenses or even meal expenses.

Each expense available shares 3 common attributes
  -cost, occurrence, GL code

(some expenses will need additional attributes).

My first thought was to use STI:

class User < ActiveRecord::Base
end

class Expense < ActiveRecord::Base
  (which have the cost, occurrence, GL code attributes)
end

class Travel < Expense
end

class Entertainment < Expense
  (and this class and some others will be needing additional attributes)
end

/////////////////

1. A user selects a month and year this expense will belong to
2. A user then selects which 'type' of expense they're going to fill out
(i.e. Travel expense)
3. User submits that form
4 Repeat as needed

I want to be able to:
  view all expenses for a user
  view all user expenses associated with a month/year
  View all user expenses via a 'type' of expense

I wanted to use STI but not all models will be all the same as some will
have additional attributes so then I thought okay maybe polymorphism
will be needed. Any help would be gratifying thank you!

Im creating an expense report.

I don't know if Im on the right path but heres what im thinking...
When submitting an expense report the user could have travel expenses,
parking expenses, cell phone expenses or even meal expenses.

Each expense available shares 3 common attributes
  -cost, occurrence, GL code

(some expenses will need additional attributes).

My first thought was to use STI:

class User < ActiveRecord::Base
end

class Expense < ActiveRecord::Base
  (which have the cost, occurrence, GL code attributes)
end

class Travel < Expense
end

class Entertainment < Expense
  (and this class and some others will be needing additional attributes)
end

/////////////////

1. A user selects a month and year this expense will belong to
2. A user then selects which 'type' of expense they're going to fill out
(i.e. Travel expense)
3. User submits that form
4 Repeat as needed

I want to be able to:
  view all expenses for a user
  view all user expenses associated with a month/year
  View all user expenses via a 'type' of expense

I wanted to use STI but not all models will be all the same as some will
have additional attributes so then I thought okay maybe polymorphism
will be needed. Any help would be gratifying thank you!

I would probably start by doing it the simple way with a single table
for expenses where the table contains all the fields for all expense
types. Then have an expense_type field (don't call it just type as
that is a reserved word in Rails). Don't worry about the fact that
some fields will be empty on some expense types. Obviously User
has_many expenses, Expense belongs_to user.

It might be worth using STI but I would start the simple way and see
how it pans out. Refactoring for that sort of change should not be
difficult.

You might want to consider having expense_type as a table so that you
can add expense types without changing the code. Expense belongs_to
expense_type, but that may or may not be appropriate for your
requirement.

Colin

It might be worth using STI but I would start the simple way and see
how it pans out. Refactoring for that sort of change should not be
difficult.

You might want to consider having expense_type as a table so that you
can add expense types without changing the code. Expense belongs_to
expense_type, but that may or may not be appropriate for your
requirement.

Colin

Ok so it would be just one form with the options of selecting the type
of expense. Then for my requirements I could just use scopes when
querying (i.e. "Give me all expenses for this user that are business
entertainment.")n essentially right?

Cause each expense has a pre defined GL code for it so would you think
it would be best to build a Case and When method to preset those before
it saves?

It might be worth using STI but I would start the simple way and see
how it pans out. Refactoring for that sort of change should not be
difficult.

You might want to consider having expense_type as a table so that you
can add expense types without changing the code. Expense belongs_to
expense_type, but that may or may not be appropriate for your
requirement.

Colin

Ok so it would be just one form with the options of selecting the type
of expense.

Now you are asking (I think) about what your user interface should
look like. That is up to you.

Then for my requirements I could just use scopes when
querying (i.e. "Give me all expenses for this user that are business
entertainment.")n essentially right?

Using scopes is often a good idea, it can save typing and aid understanding.

Cause each expense has a pre defined GL code for it so would you think
it would be best to build a Case and When method to preset those before
it saves?

I have no idea what you are asking here. Sorry.

Colin

I have no idea what you are asking here. Sorry.

Colin

I meant using a case statement. Sorry that was very poorly worded.

def which_expense_type(expense)

case expense.expense_type

  when "Travel"
    expense.gl_code = arbitrary_number
  when "Parking"
    expense.gl_code = arbitrary_number
end

end

Is the gl code a unique number that identifies the type? If so then
that should be stored in the db but the string should not, since it
can be determined from the string. Alternatively put the string in
the db and not the code. It is almost always a bad idea to store
redundant data in the db.

Colin

Is the gl code a unique number that identifies the type? If so then
that should be stored in the db but the string should not, since it
can be determined from the string. Alternatively put the string in
the db and not the code. It is almost always a bad idea to store
redundant data in the db.

Yeah, the gl_code will be a set number. For instance all travel
expenses will have a gl code of 8907 and all employee meals will have a
gl code of 5201 and so on.

Cause I'd like when a user chooses a type of expense that that expenses
gl_code will be saved as appropriate.

This is because the final step in the reporting is to gather the total
cost of each gl code and display it. Some expenses share the same gl
code too.. make sense ?

It is important to separate user interface issues from database
issues. There is no need (from what I understand) to have both name
and gl code in the database as if you (the programmer) knows one then
you are able to determine the other. If you want both on the UI then
that is no problem, just work the other one out when you need to
display it.

Colin

It is important to separate user interface issues from database
issues. There is no need (from what I understand) to have both name
and gl code in the database as if you (the programmer) knows one then
you are able to determine the other. If you want both on the UI then
that is no problem, just work the other one out when you need to
display it.

OKay okay so basically instead of categorizing them by their name as a
string just categorize them by their gl_code and the gl_code is what
will be saved in the db and I can just work out displaying the expense
type name on the UI.

The only thing is the employee that is inputing their expense doesnt
always know the gl_code or if ever because to them its meaningless (to
the endpoint person its important)

So maybe When they choose what kind of expense it is make it a dropdown
list with the Expense type name and the gl_code and then it'll just save
the gl_code.

This would be a belongs_to has_many relationship between expenses and
gl_codes

PS thanks for helping thus far Colin. I'm the only developer here at my
work and have no one to bounce ideas off of or thoughts so this has been
helpful

That was not what I thought you were doing, I thought you were just
going to include the gl_code in the expenses table. However there may
well be an argument for having an expense_types table with
Expense belongs_to expense_type
ExpenseType has_many expenses

In that case you could put both the string and gl code in the expense
type table and there is no need for any code to work out one from the
other. Note the difference here is that each expense type will only
be saved in the db once so there is no redundant data. As you
originally described it I thought you were going to save both gl code
and string in each expense record so there would be multiple instances
of each in the db.

Colin

That was not what I thought you were doing, I thought you were just
going to include the gl_code in the expenses table. However there may
well be an argument for having an expense_types table with
Expense belongs_to expense_type
ExpenseType has_many expenses

I think this is the most appropriate way to handle this at this stage.
Then I'll just build all the possible expense types that our company
allows in the database so the dropdown would make sense then..

EXPENSE
occurrence
cost
description
expense_type_id

EXPENSE_TYPE
name
gl_code

Grab an expense type
e = ExpenseType.where(gl_code: 9090)

display me the expenses that relate to this gl_code
e.expenses

Looks good to me.

Colin

Got the main feature done. Thank you for your help Colin and talk
throughs. What a difference it makes!