How to model the associations for a task application? - ruby-on-rails

I'm working on a goal completion application, where there can be Goals, Milestones, and Tasks. Milestones belong to goals, goals can have many milestones, and tasks can belong to either goals, milestones, or stand on their own. The information I want to store in each model is as follows:
Goal content:string, est_completion_date:date completed:boolean, completion_date:date
Milestone content:string, est_completion_date:date completed:boolean, completion_date:date
Task content:string, occur_on:date completed:boolean, completion_date:date, days:?
The 'occur_on' field for the Task model is to schedule the task for a custom date. The 'days' field stores what days of the week the task should happen, if it's recurring.
I have two questions.
1) I read about single table inheritance and wondered if this would work for me. Every model is pretty much the same except the Task model has 'days' and 'occur_on', but doesn't have 'est_completion_date'. What's the best way to model all of these associations?
2) I'm not quite sure how to best store the information regarding what days of the week a task should occur on. Should I just make it an associative array with boolean values for each day, or should I have separate fields for each day in the table?

1) Your single table inheritance question is well answered here.
2) I recommend keeping it simple for your days column. Just store a string of digits, with each digit representing a day. So 245 might represent Monday, Wednesday & Thursday. To find tasks that occur on Wednesday you can query with a regular expression, e.g. select * from tasks where days regexp("4");

Related

FactLoanVolume - One or Many Fact Tables

I am designing a Fact table to report on loan volume. The grain is one row per loan transaction. A loan has a few major milestones that we report on: In order of sequence, these are Lock Volume, Loan Funding Volume and Loan Sales Volume.
I have Lock Date, Loan Funding Date and Loan Sale Date as FK (there are other dimensions in addition to these) in the Fact table to role playing dimensions off my DimDate table.
My question is, should I create separate Fact Tables to report volume for each major milestone or should I keep all of this in one Fact Table and use a "far in the future" date (e.g., 12/31/2099) for a milestone on a loan that has not been met?
I have read the Kimball books but I didn't find a definitive answer(if one even exists).
Thanks
You may profit from immutable design, by setting the granularity more fine to the milestone level.
This gives you columns
transaction_id
milestone_type
milestone_date
in you fact table. The actual milestone of a transaction is the milestone from the last (most recent) record.
The one adavatage is that you may add new milestone types in the future, but the main gain is, that you never update your fact table - you use inserts only.
You may safe rollback a wrong ETL load, simple by deleting the records; which is while using updates much complicated.
You may also implement more complicated state diagrams, e.g. in case when some milestone is revoked and the transaction falls back in the previous state.
The question if you use one fact table or more depends on the fact if your milestones are homogenous or not. If the milestones have distinct attributes, you may get a more clean desing using dedicated fact tables, but the queries get complicated.
You would rather have only one Fact Table.
That following question and its conversation answer pretty well to the general question of " One or multiple fact tables? ", but maybe not to how to deal with your specific problem of dates.

What is best practice for handling application configuration?

I'll phrase the question in the context of my application but I think it does have a wider scope generally for configuration. My application allows companies to track absences and holidays for its employees. One of the benefits is that it will automatically increase a person's holiday entitlement based on rules set by the employer. The intention is for the company to choose between:
A) automatically increase an employee's entitlement by a set number of days every year e.g. on 1 January each year, holiday entitlement increases by 1 day; or
B) an employee's entitlement increases based on length of service e.g. after 2 years' employment, entitlement increases by 2 days
What is the best way to implement this functionality? The first option is fairly simple to implement as I have track the start/end dates of each leave year and the increment for each employee can be stored as an integer.
I guess I'm looking for best practice solutions to store the chosen method; how to store the relevant options and all in an extensible format allowing me to add further methods later.
I'm working with Ruby on Rails but the question is probably relevant to other languages.
Thanks
Robin
What about: Store the balance in Employee. Employee belongs to Company. When the time comes, set the balance by using something like
self.company.set_balance(self.balance)
So your employee assessor runs over all the employees and asks the company to recalculate its balance.
If it's a global policy, then you don't need to tell Company who the employee is, but if you needed to have special cases, you could pass the Employee to the set_balance method so that it would have more information about the employee being recalculated.
As for the Compay's strategy in how to increase the days, I'd put it in a model to limit the code changes needed if the strategy is changed.
If it's a simple rule, maybe just keep it in a key/value pair:
"holiday_entitlement"/"flat"
or
"holiday_entitlement"/"length of service"
I would not keep the the values (1 or 2) in the DB in order to avoid smart employees hacking into the DB and putting 'favourable' values in there :)

How to handle ids and polymorphic associations in views if compound keys are not supported?

I have a Movie plan table:
movie_plans (id, description)
Each plan has items, which describe a sequence of movies and the duration in minutes:
movie_plan_items (id, movie_plan_id, movie_id, start_minutes, end_minutes)
A specific instance of that plan happens in:
movie_schedules (id, movie_plan_id, start_at)
However the schedule items can be calculated from the movie_plan_items and the schedule start time by adding the minutes
create view movie_schedule_items as
select CONCAT(p.id, '-', s.id) as id,
s.id as movie_schedule_id,
p.id as movie_plan_item_id,
p.movie_id, p.movie_plan_id,
(s.start_at + INTERVAL p.start_minutes MINUTE) as start_at,
(s.start_at + INTERVAL p.end_minutes MINUTE) as end_at
from movie_plan_items p, movie_schedules s
where s.movie_plan_id=p.movie_plan_id;
I have a model over this view (readonly), it works ok, except that the id is right now a string.
I now want to add a polymorphic property (like comments) to various of the previous tables. Therefore for movie_schedule_items I need a unique and persistent numeric id.
I have the following dilemma:
I could avoid the id and have movie_schedule_items just use the movie_plan_id and movie_schedule_id as a compound key, as it should. But Rails sucks in this regard.
I could create an id using String#hash or a md5, thus making it slower or collision prone (and IIRC String#hash is no longer persistent across processes in Ruby 1.9)
Any ideas on how to handle this situation?
I think you've built your models a little too complex.
MoviePlan is a pattern that you use for every day's schedule of movies? I'd very much recommend to drop the MovieSchedule and instead allow the user to copy an existing MoviePlan. This will a) make your design simplier and b) allow more freedom for the user as schedules often differ in reality. An extra matinee on Saturdays, a special foreign movie on wednesdays, that's all what I see at my favourite cinema.
Lastly, making comments on a movie of a specific movie plan and schedule doesn't make any sense to me, or is this some customer management thing like "my seat in the 7pm show of Funny Movie was dirty"?

How to best model and search seasonal availability with Rails

So I have an app where I am tracking a number of things, including flowers. Depending on the type of flower they can be available from places during certain spans of time during the year. Sometimes they can even be available during multiple spans of time (eg domestically from Mar-Jun, but can be found internationally from Sept-Dec).
What I am looking to be able to do is search for a specific date and determine all the different flowers that would be available on that date.
My idea was to have an Availability model which had a belongs_to relationship with a Flower. It would have a start_date, an end_date, and a flower_id. The problem was that dates in rails tend to be specific points in time, eg 2009-10-13. If I said a flower was available from 2009-10-01 - 2009-12-31 when 2010 came around I wouldn't see it as available.
So then I thought maybe I could have some sort of cron job that went through daily and changed the years on availability records as their end dates came up.
Maybe this is the right approach, but it feels a bit clunky. I looked through a few gems/plugins and couldn't find anything in particular that would fit my need.
Anyone have any insight?
Thanks in advance...
Given the cyclical nature of months it can be difficult perform a query to quickly select months where a given set of flowers is available.
I like the availability model, but think you should be saving just the month number (eg: October is saved as 10 in the start_month/end_month fields). Use Date::MONTHNAMES to make things human readable. (eg: Date::MONTHNAMES[10] => "October")
This allows you to easily form a named scope in Availabilities to choose what's available now.
class Flower < ActiveRecord::Base
has_many :availabilities
named_scope :available_today, lambda
month = Date.today.month
{:include => :availabilities, :conditions =>
["(availabilities.start_month < availabilities.end_month AND \
availabilities.start_month <= ? AND availabilities.end_month >= ?) \
OR (availabilities.start_month > availabilities.end_month AND \
availabilities.start_month >= ? AND availabilities.end_month <= ?)",
month, month,month,month]}
named_scope :red, :conditions => {:colour => "red"}
end
Now you can do Flower.available_today.red to get a list of red flowers available now.
Unfortunately the named scope might populate the association with the availabilities (Flower.available_today.first.availabilities) that you don't want. I can't be sure without testing it, and I don't have the environment to do so right now. Worst case scenario you can use #flower.availabilities.select with similar arguments to the queries to prune the list.
I like the Availability model idea, but I'd store just a start_month and end_month (both integers) and a notes field (for stuff like "Internationally" or "Domestically"). Then when you have a date, you just get the month field and compare to the set of ranges you have for each flower.
That might be a little compute-intensive if you have a lot of flowers. You could instead store a single Availability row for each flower, with 12 integers - one for each month - and 12 notes fields. Or if you won't have a lot of notes, you have an AvailabilityNotes model. Availability then has_many :availability_notes.
If it's for seasonal items, you could just have a (start/end)month or season field.
First of all, is there a customer demand to get this "right?" Who wants this feature, and how do you know they want it? Have you modeled the user's workflow to determine how this actually fits into ordering behavior? Do you really take orders for flowers a year or more in advance? Is availability only based on the season -- there's no dependency on suppliers or other events that can change year-to-year? And are you anticipating that you'll always have the same inventory next year that you will this year? Or is pinning an availability date on a flower not a guarantee?
If this is just for general information purposes -- you'd like people to know what sorts of flowers they can order at what times of year -- then I wouldn't give the user a "pick a date" function at all. I'd just give them a dropdown: either for four values for seasons, or twelve for months. If they just want to know "Is it likely I can get lilies for my mom's birthday?" that's fully sufficient.
And you could model it very simply, with four or twelve boolean values in your model, and four or twelve checkboxes on your flower create/edit form. (Yeah, I know, it's "purer" to do a :has_many association, but unnecessary; the number of months in the year isn't going to change.)

Keeping the history of model associations

I have multiple models that need to have their history kept pretty much indefinitely or at least a very long time. The application I would keep track of daily attendance statistics for people in different organizations, and a couple of other similar associations. I've realized that I can't ever delete users due to the user not showing up in a query for attendance anytime before said user was deleted. The problem I'm having is finding a nice way of keep track of old associations as well as querying on those old associations.
If I have a connecting table between Users and Organizations, I could just add a new row with the new associations between a User and the Organization the user belongs to, and query on the old ones based on the date, but I really don't have any elegant way of doing this, everything just feels ugly. I was just wondering if anyone has dealt with anything like this before, and maybe had a solution they had already implemented. Thanks.
From a modeling point, the relationship sounds like the one between Employee and Employer, namely Employment. This would hold a reference to both Employee and Employer along with some notion of the TimePeriod (ie, startDate and end Date). If you wanted to query 'active' employees then they are all the ones with a startDate <= Now() && endDate >= Now(), 'terminated' employees have endDate < Now(), etc.
I can't tell in your case what the relationship is between Users and Organizations, and what makes the relationship start and end, but a concept similar to Employment, Membership, Enrollment or Contract is likely there. When you say daily attendance, is it not daily over a period of time? The time period is the basis for your queries.
Hope that helps,
Berryl
Create an is_deleted field so that you can still query those "deleted" users, but modify your code so that they will behave everywhere else as if they are deleted. Then you never need to actually delete the row and lose data.
There are a number of plugins that keep track of revisions to models, including their associations. Take a look at this search for revision-related plugins.

Resources