How to best model and search seasonal availability with Rails - ruby-on-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.)

Related

database design for composite elements

I'm building a site that tracks donations and sales of items in a school auction.
Items can be sold individually or in lots, which are just groups of items bundled for sale as a single unit (like a gift certificate for a dinner Item bundled with a gift certificate for movie tickets Item).
Both of these things (Items and Lots) share fields like name, description, value. But Items have additional fields, like the donor, restrictions of use, type of item, etc.
I started by creating a table called Lot and an association table that lets Lots contain 1+ Items.
That works great for Lots. But that leaves me with a problem:
When Buyers win I need to record the win and the price. I'm doing that with a Win table that associates the Buyer with the Lot and the winning price.
But how do I deal with all the Items that aren't assigned to Lots? Should every item be in a Lot, just singly? That would make sense because it would work with the Win table scheme above, but I would need to automatically create a Lot for every Item that isn't already in another Lot. Which seems weird.
I'm sure this is a simple problem, but I can't figure it out!
Thanks!
Your approach of treating every item as a lot should be the winning one. It may sound weird, but it will make things way easier in the long run.
I have to deal on a daily base with a database where a similar problem was 'solved' the other way round, meaning keeping bundles of items and items apart and that proved to be a great pita (and for sure I'm not talking about a flat round bread here).
This database is both backbone for statistical evaluations and a bunch of (web) applications and on countless occasions I run into trouble when deciding which table to chose or how to level the differences between those two groups in querying and in coding.
So, even if your project will be rather small eventually, that is a good idea.
Yes, you need to provide a method to put every item in a lot, but this trouble is to be taken just once. On the other hand your queries wouldn't become significantly more complex because of that 'extra' table, so I'd definitely would chose this way.
It sounds like you have an Auction model that could have one or many Items. Then you could have two different types of Auctions, Auction::Single and Auction::Lot. Price would be a column on Auction. Auction has many Bids which is a join model between the Auction and the User (or Bidder). That join model would also store the bid price. When the Auction is over, you could create a separate Win record if you want, or just find the Winner through the highest Bid from Auction.
It would be helpful if you showed some code. But, what you want is a polymorphic association. So, something like:
class Item
has_one :win, as: :winnable
belongs_to :lot
end
class Lot
has_one :win, as: :winnable
has_many :items
end
class Win
belongs_to :buyer
belongs_to :winnable, polymorphic: true
end

Working with different date fields. How to approach towards an easier search engine? Rails 3.2

I built a small site where I gather information of some cultural events happening in the area. I want to extend the Event model so it can handle 3 different 'case scenario' of events.
'i.e. Single'. Normal event with start date and finish date.
'i.e. Band on tour'. Same event but happening at different times.
'i.e. Museum'. Monday to Sunday timetable.
I thought that the best approach for the 1 and 2 types will be:
Event model
# holds title, description, price....
has_many :dates
accepts_nested_attributes_for :dates
Date model
# holds start_time(:datetime) and finish_time(:datetime)
belongs_to :events
I am not sure how to approach the 3rd type. Or what is more important, how to build it in a way that makes future interactions easier to code... like building a SEARCH engine.
Idea:
Building another model called Timetable?
This could hold:
boolean types -> Mon - Tue... -Sun
time type -> Mon_start - Tue_start... - Sun_start - Mon_finish - Tue_finsih... - Sun_finish.
However, this seems pretty complicated to update the search engine(which has a date field/parameter) to iterate through all these 3 types.
Any ideas/experience which may clarify the path to take? Many thanks in advance!
One way that would work well would be to make Date abstract, and then make three more models that extend Date.

Rails Filtering Best-Practices

I have a web app that has the following models: Shifts, Years, Checkouts, Sales and Visitors.
A Shift has_many Checkouts, Sales, Visitors
A Year has_many Shifts
Checkouts, Sales and Visitors belong_to Shift
Shifts belong_to Year
In my app, I want to have many different years present, although only ONE is active at any given time. When I display Shifts, for example, I only want Shifts from the active year to be displayed. That's easy enough.
What I'm having a real hard time with is writing a query to get all of the checkouts from the active year. Is there a simple way to go about doing this? The active year is actually set in a session variable called session[:current_year_id]. I thought the best way to go about doing it would be to do something like:
#checkouts = Shift.where('year_id = ?',session[:current_year_id]).checkouts
But that's not working for me. What do I need to change to get that to work?
Note that checkouts, sales and visitors DO NOT have their own year_id. They have a year_id through the shift that they belong to.
Resolved:
I upvoted all the answers, since all helped. I used the for_year lambda expression. I've upvoted all the answers.
The final answer was to use:
Shift.for_year(session[:current_year_id]).collect{ |shift| shift.checkouts }
You can create a scope in Shift model that takes current year as parameter:
class Shift < ActiveRecord::Base
has_many :checkouts
scope :for_year, lambda { |current_year_id| where('year_id = ?', current_year_id) }
end
and in the controller, you can get the checkouts for current year by chaining to the scope:
Shift.for_year(session[:current_year_id]).map(&:checkouts)
Using .where returns a relation, so there are two possible answers based on your intention.
If you want to find the checkouts belonging to the first shift, do:
#checkouts = Shift.where('year_id = ?',session[:current_year_id]).first.checkouts
If you want all checkouts for all shifts, do:
#checkouts = Shift.where('year_id = ?',session[:current_year_id]).collect{|shift| shift.checkouts}
You could try:
Shift.find_all_by_year_id(session[:current_year_id])
This assumes current_year_id is in the session.
I have had problems with using .where, which I fixed by using a dynamic finder.

Creating a Calendar/Planner Application - Ruby on Rails

I am considering developing an application using Ruby on Rails that is a planner of sorts. I would like to give a user the ability to see a list of days, click a particular day, and then add things like: Meals, Expenses, Events, Todos, and Exercises. Really I am doing this for me and my growing family.
I am curious with how best to implement this. I can certainly see that Meals, Expenses, etc. need to belong_to :user but I am curious how to implement the belongs_to :day or something like that. Using the created_at or updated_at wouldn't necessarily allow me to provide views for future dates.
I can see how if I created a Days table and then added days through a time and date field that this would work but seems a little strange to ask people to create the actual days.
Or perhaps instead of that I could just create links to variables that search for #today, #tomorrow, but that would get messy.
I have browsed for gems/plugins but can't find one that works. Ideally a person would be able.
Anyone have any thoughts on how to implement something like this?
There are a number of existing Rails calendars, such as http://github.com/elevation/event_calendar or http://github.com/topfunky/calendar%5Fhelper.
However, to answer your specific question about dates: I don't think there's any need to have Day as a model; simply give each event a start date and time, and an end date and time. Remember that Ruby makes it easy to search based on ranges, so "give me all of the events next week" is a cinch if each event has dates and times associated with it.
I'll give it a shot...
Two tables; users and events. A user has many events and an event belongs to a user. Meal, Expenses, etc. are various types of Event. Within events, you can have fields for start and end time of the events. If needed (lets say an events last over multiple days), you could remove the day/time when events occurs into it's own table.
This way, when displaying the calendar for a user, you can find all the events for that date. If none are found, then display nothing.
What do you think?
I would add a model called "Events" and have a properties of the model to represent start date/time, end date/time. I do not think you need a Days model, you can generate your calendar view from the Date class built into ruby.
I have done same kind of project for the Event management in training institute. At there I used event_calender plug in with rails. (enter link description here)
In there we just need to create Event model only. Then we can easily work with that.

Temporal data with Rails / Active Record

I'm looking for ideas/information about managing temporal data with Active Record (Rails). One example would be the emplyoment history (working 100% in january, but only 80% from february up to now). This proably would be easy to tackle with a traditional 'has-many :eployment_parts'. But there's another case where the user can plan something like a todo list, which the user can change over time (this todo is valid from Jan-March, another one is valid from Jan-April, and then with changed details from May to August).
I know, there's no silver bullet solution for these kind of requirements, but I'd like to collect here some ideas/docmentations/plugins about this topic. It looks like there hasn't been done much in this area for rails, at least nothing which got public.
Please, if you have an idea, link or thought, drop a short answer!
Links so far:
Eric's random thoughts, blog entry about temporal data in rails
Bi-Temporal PostgreSQL, helps managing temporal data in postgres (w/o rails)
Richard T. Snodgrass's book "Developing Time-Oriented Database Applications in SQL" can be downloaded from his homepage (out of print)
we had the need to keep historical data of all changes to database records, and be able to query data as-of-time, without impacting performance of querying current data.
The solution we envisioned is a Slowly-Changing dimension type 2, with history tables. The implementation is a Ruby gem that requires PostgreSQL 9.3 and fits nicely in Active Record extending it with the temporal framework (e.g. Foo.as_of(1.year.ago).bars).
You can find the code here: https://github.com/ifad/chronomodel :-)
You need to detail what you want to do a bit more.
For example, what "resolution" do you need? Do you plan to record every worked hour of every day? Or just the average montly workload? Per week, maybe?
Also, what do you want to do with holidays, and sick days?
(EDIT - answering to the comment below)
In your case I'd go with a model similar to this one:
class WorkSlice < ActiveRecord::Base
belongs_to :employee
validates_presence_of employee_id, start_date, end_date, percentage
def calculate_hours
#employees might have different hours per day (i.e. UK has 7, Spain has 8)
employee.hours_per_day * self.calculate_days
end
def calculate_days
#days between start_day and end_day that are not sick days, holidays or weekends
workdays = ... #this depends on how you model holidays, etc
return workdays * self.percentage
end
end
The only association you need is with "employee", as far as I know. A method on employee would allow you to see, for example, how "free" that eployee is on a given date.
"I know, there's no silver bullet solution for these kind of requirements,"
That does depend a bit on how silver you need your bullet to be.
Anyhow. You might find the following stuff interesting too :
(a) "An Overview and Analysis of TSQL2" by Hugh Darwen and C.J. Date. A link is on www.thethirdmanifesto.com in the "Papers" section at the bottom.
(b) "Temporal Data and the Relational Model", a complete book by the same authors plus Nikos Lorentzos. Contains a different, complete, proposal plus very sound justifications why they believe that proposal to be better.
(c) You can find an implementation called SIRA_PRISE, written by me, based on the ideas from (b), on shark.armchair.mb.ca/~erwin

Resources