Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Lets you find ActiveRecord objects by year, month, fortnight, week and more!
Ruby

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
lib
spec
tmp
.gitignore
.travis.yml
CHANGELOG.md
Gemfile
MIT-LICENSE
README.md
Rakefile
UPGRADING
by_star.gemspec
cleaner.rb

README.md

by_*

Build Status

by_* (by_star) is a plugin that allows you to find ActiveRecord and/or Mongoid objects given certain date objects.

Installation

Install this gem by adding this to your Gemfile:

gem 'by_star', :git => "git://github.com/radar/by_star"

Then run bundle install.

If you are using ActiveRecord, you're done!

Mongoid users, please include the Mongoid::ByStar module for each model you wish to use the functionality. This is the convention among Mongoid plugins.

class MyModel
  include Mongoid::Document
  include Mongoid::ByStar

What it does

This was originally crafted for only finding objects within a given month, but now has extended out to much more. It now supports finding objects for:

  • A given year
  • A given month
  • A given fortnight
  • A given week
  • A given weekend
  • A given day
  • A given quarter
  • The weeks of a given month as shown on a calendar
  • The current weekend
  • The current work week
  • The Past
  • The Future
  • Between certain times
  • Before a specific record
  • After a specific record

All methods return scopes. I love these. You love these. Everybody loves these.

It also allows you to do nested finds on the records returned which I personally think is the coolest feature of the whole plugin:

Post.by_month(1).include(:tags).where("tags.name" => "ruby")

If you're not using the standard created_at field: don't worry! I've covered that scenario too.

Scoping the find

You can treat all by_* methods exactly how you would treat normal, every-day ActiveRecord scopes. This is because all by_* methods return ActiveRecord::Relation objects, with the exception of previous and next, which return a single record. You can call them like this:

Post.by_month.your_scope

Where my_special_scope is a named_scope you have specified.

You can also call typical ActiveRecord::Relation methods on the by_* methods (like I showed before):

Post.by_month.include(:tags).where("tags.name" => "ruby")

Want to count records? Simple:

Post.by_month.count

Time-Range Type Objects

If your object has both a start and end time, you may pass both params to by_star_field:

by_star_field :start_time, :end_time

By default, ByStar queries will return all objects whose range has any overlap within the desired period (permissive):

MultiDayEvent.by_month("January") #=> returns MultiDayEvents that overlap in January, even if they start in December and/or end in February

If you'd like to confine results to starting and ending within the given range, use the :strict option:

MultiDayEvent.by_month("January", strict => true) #=> returns MultiDayEvents that both start AND end in January

By Year (by_year)

To find records from the current year, simply call the method without any arguments:

Post.by_year

To find records based on a year you can pass it a two or four digit number:

Post.by_year(09)

This will return all posts in 2009, whereas:

Post.by_year(99)

will return all the posts in the year 1999.

You can also specify the full year:

Post.by_year(2009)
Post.by_year(1999)

By Month (by_month)

If you know the number of the month you want:

Post.by_month(1)

This will return all posts in the first month (January) of the current year.

If you like being verbose:

Post.by_month("January")

This will return all posts created in January of the current year.

If you want to find all posts in January of last year just do

Post.by_month(1, :year => 2007)

or

Post.by_month("January", :year => 2007)

This will perform a find using the column you've specified.

If you have a Time object you can use it to find the posts:

 Post.by_month(Time.local(2012, 11, 24))

This will find all the posts in November 2012.

By Calendar Month (by_calendar_month)

Finds records for a given month as shown on a calendar. Includes all the results of by_month, plus any results which fall in the same week as the first and last of the month. Useful for working with UI calendars which show rows of weeks.

Post.by_calendar_month

Parameter behavior is otherwise the same as by_month

By Fortnight (by_fortnight)

Fortnight numbering starts at 0. The beginning of a fortnight is Monday, 12am.

To find records from the current fortnight:

Post.by_fortnight

To find records based on a fortnight, you can pass in a number (representing the fortnight number) or a time object:

Post.by_fortnight(18)

This will return all posts in the 18th fortnight of the current year.

Post.by_fortnight(18, :year => 2012)

This will return all posts in the 18th fortnight week of 2012.

Post.by_fortnight(Time.local(2012,1,1))

This will return all posts from the first fortnight of 2012.

By Week (by_week)

Week numbering starts at 0. The beginning of a week is Monday, 12am.

To find records from the current week:

Post.by_week

To find records based on a week, you can pass in a number (representing the week number) or a time object:

Post.by_week(36)

This will return all posts in the 37th week of the current year (remember week numbering starts at 0).

Post.by_week(36, :year => 2012)

This will return all posts in the 37th week of 2012.

Post.by_week(Time.local(2012,1,1))

This will return all posts from the first week of 2012.

By Weekend (by_weekend)

If the time passed in (or the time now is a weekend) it will return posts from 12am Saturday to 11:59:59PM Sunday. If the time is a week day, it will show all posts for the coming weekend.

Post.by_weekend(Time.now)

By Day (by_day or today)

To find records for today:

Post.by_day
Post.today

To find records for a certain day:

Post.by_day(Time.local(2012, 1, 1))

You can also pass a string:

Post.by_day("next tuesday")

This will return all posts for the given day.

By Quarter (by_quarter)

Finds records by 3-month quarterly period of year. Quarter numbering starts at 1. The four quarters of the year begin on Jan 1, Apr 1, Jul 1, and Oct 1 respectively.

To find records from the current quarter:

Post.by_quarter

To find records based on a quarter, you can pass in a number (representing the quarter number) or a time object:

Post.by_quarter(4)

This will return all posts in the 4th quarter of the current year.

Post.by_quarter(2, :year => 2012)

This will return all posts in the 2nd quarter of 2012.

Post.by_week(Time.local(2012,1,1))

This will return all posts from the first quarter of 2012.

Tomorrow (tomorrow)

This method has been shown to be shifty when passed a Date object, it is recommended that you pass it an ActiveSupport::TimeWithZone object instead.

To find all posts from the day after the current date:

Post.tomorrow

To find all posts after a given Date or Time object:

Post.tomorrow(Date.today + 2)
Post.tomorrow(Time.now + 5.days)

You can also pass a string:

Post.tomorrow("next tuesday")

Yesterday (yesterday)

This method has been shown to be shifty when passed a Date object, it is recommended that you pass it an ActiveSupport::TimeWithZone object instead.

To find all posts from the day before the current date:

Post.yesterday

To find all posts before a given Date or Time object:

Post.yesterday(Date.today + 2)
Post.yesterday(Time.now + 5.days)

You can also pass a string:

Post.yesterday("next tuesday")

Before (before)

To find all posts before the current time:

Post.before

To find all posts before certain time or date:

Post.before(Date.today + 2)
Post.before(Time.now + 5.days)

You can also pass a string:

Post.before("next tuesday")

For Time-Range type objects, only the start time is considered for before.

After (after)

To find all posts after the current time:

Post.after

To find all posts after certain time or date:

Post.after(Date.today + 2)
Post.after(Time.now + 5.days)

You can also pass a string:

Post.after("next tuesday")

For Time-Range type objects, only the start time is considered for after.

Between (between or between_times)

To find records between two times:

Post.between(time1, time2)

Also works with dates:

Post.between(date1, date2)

between_times is an alias for between:

Post.between_times(time1, time2)  #=> results identical to above

Previous (previous)

To find the record prior to this one call previous on any model instance:

Post.last.previous

You can specify a field also:

Post.last.previous("published_at")

For Time-Range type objects, only the start time is considered for previous.

Next (next)

To find the record after this one call next on any model instance:

Post.last.next

You can specify a field also:

Post.last.next("published_at")

For Time-Range type objects, only the start time is considered for next.

Not using created_at? No worries!

If your database uses something other than created_at for storing a timestamp, you can specify the field option like this:

Post.by_month("January", :field => :something_else)

All methods support this extra option.

Or if you're doing it all the time on your model, then it's best to use by_star_field at the top of your model:

class Post < ActiveRecord::Base
  by_star_field :something_else
end

Mongoid

Mongoid is only tested/supported on version 3.0+

Testing

Specify a database by supplying a DB environmental variable:

bundle exec rake spec DB=sqlite

You can also take an ORM-specific test task for a ride:

bundle exec rake spec:active_record

Have an Active Record or Mongoid version in mind? Set the environment variables ACTIVE_RECORD_VERSION and MONGOID_VERSION to a version of your choice. A version number provided will translate to ~> VERSION, and the string master will grab the latest from Github.

# Update your bundle appropriately...
ACTIVE_RECORD_VERSION=4.0.0 MONGOID_VERSION=master bundle update

# ...then run the specs
ACTIVE_RECORD_VERSION=4.0.0 MONGOID_VERSION=master bundle exec rpsec spec

Collaborators

Thanks to Thomas Sinclair for the original bump for implementing it. I would like to thank #rubyonrails for their support and the following people:

  • Mislav Marohnic
  • August Lilleas (leethal)
  • gte351s
  • Sam Elliott (lenary)
  • The people who created Chronic
  • Erik Fonselius
  • Johnny Shields (johnnyshields)

Suggestions?

If you have suggestions, please contact me at radarlistener@gmail.com

Something went wrong with that request. Please try again.