Last active
January 31, 2023 01:44
-
-
Save nathancolgate/4998196 to your computer and use it in GitHub Desktop.
How I built a rails interface on top of the amazing IceCube ruby gem. Video of final product: http://youtu.be/F6t-USuWPag
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
= bootstrap_form_for @event, html: {class: 'form-horizontal', novalidate: 'novalidate'} do |f| | |
.row | |
.span6 | |
= f.text_field :name, class: 'span4' | |
= f.text_area :description, class: 'span4', rows: 5 | |
= f.select :location_id, options_from_collection_for_select(Place.all, 'id', 'name', f.object.location_id), include_blank: true | |
= f.select :host_id, options_from_collection_for_select(Place.all, 'id', 'name', f.object.host_id), include_blank: true | |
.span6 | |
= f.check_box :is_all_day | |
= f.date_select :from_date, {}, {style: 'width:auto;'} | |
.event_time | |
= f.time_select :from_time, {:minute_step => 15}, {style: 'width:auto;'} | |
= f.date_select :to_date, {}, {style: 'width:auto;'} | |
.event_time | |
= f.time_select :to_time, {:minute_step => 15}, {style: 'width:auto;'} | |
.event_time | |
= f.time_zone_select :time_zone, ActiveSupport::TimeZone.us_zones, :default => "Central Time (US & Canada)" | |
= f.select :repeats, Event::RepeatsOptions | |
= render partial: 'repeats_daily_options', locals: {f: f} | |
= render partial: 'repeats_weekly_options', locals: {f: f} | |
= render partial: 'repeats_monthly_options', locals: {f: f} | |
= render partial: 'repeats_yearly_options', locals: {f: f} | |
#repeats_options.event_option | |
= f.select :repeat_ends, Event::RepeatEndsOptions | |
#event_repeat_ends_on | |
= f.date_select :repeat_ends_on, {}, {style: 'width:auto;'} | |
.form-actions | |
= f.submit 'Save' | |
- content_for :last_javascripts do | |
:javascript | |
$(function() { | |
var toggle_repeats_yearly_on = function(){ | |
if($('#event_repeats_yearly_on').is(':checked')){ | |
$('#event_repeats_yearly_on_options').show(); | |
} else { | |
$('#event_repeats_yearly_on_options').hide(); | |
} | |
} | |
toggle_repeats_yearly_on(); | |
$('#event_repeats_yearly_on').on('change',function(){ | |
toggle_repeats_yearly_on(); | |
}); | |
var toggle_event_times = function(){ | |
if($('#event_is_all_day').is(':checked')){ | |
$('.event_time').hide(); | |
} else { | |
$('.event_time').show(); | |
} | |
} | |
toggle_event_times(); | |
$('#event_is_all_day').on('change',function(){ | |
toggle_event_times(); | |
}); | |
var toggle_event_options = function(){ | |
$('.event_option').hide(); | |
switch ($('#event_repeats').val()) | |
{ | |
case 'never': | |
// Nothing | |
break; | |
case 'daily': | |
$('#repeats_options').show(); | |
$('#repeats_daily_options').show(); | |
break; | |
case 'weekly': | |
$('#repeats_options').show(); | |
$('#repeats_weekly_options').show(); | |
break; | |
case 'monthly': | |
$('#repeats_options').show(); | |
$('#repeats_monthly_options').show(); | |
break; | |
case 'yearly': | |
$('#repeats_options').show(); | |
$('#repeats_yearly_options').show(); | |
break; | |
} | |
} | |
toggle_event_options(); | |
$('#event_repeats').on('change',function(){ | |
toggle_event_options(); | |
}); | |
var toggle_repeat_ends_on = function(){ | |
switch ($('#event_repeat_ends').val()) | |
{ | |
case 'never': | |
$('#event_repeat_ends_on').hide(); | |
break; | |
case 'on': | |
$('#event_repeat_ends_on').show(); | |
break; | |
} | |
} | |
toggle_repeat_ends_on(); | |
$('#event_repeat_ends').on('change',function(){ | |
toggle_repeat_ends_on(); | |
}); | |
var toggle_repeats_monthly = function(){ | |
switch ($('#event_repeats_monthly').val()) | |
{ | |
case 'each': | |
$('#event_repeats_monthly_each').show(); | |
$('#event_repeats_monthly_on').hide(); | |
break; | |
case 'on': | |
$('#event_repeats_monthly_each').hide(); | |
$('#event_repeats_monthly_on').show(); | |
break; | |
} | |
} | |
toggle_repeats_monthly(); | |
$('#event_repeats_monthly').on('change',function(){ | |
toggle_repeats_monthly(); | |
}); | |
}); | |
- content_for :first_styles do | |
:css | |
#repeats_options {display:none;} | |
#repeats_daily_options {display:none;} | |
#repeats_weekly_options {display:none;} | |
#repeats_monthly_options {display:none;} | |
#repeats_yearly_options {display:none;} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%fieldset{id: 'repeats_daily_options', class: 'event_option'} | |
= f.number_field :repeats_every_n_days |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%fieldset{ id: 'repeats_monthly_options', class: 'event_option'} | |
= f.number_field :repeats_every_n_months | |
= f.select :repeats_monthly, Event::RepeatMonthlyOptions | |
#event_repeats_monthly_each.control-group | |
%label.control-label Each | |
.controls | |
- Event::DaysOfTheMonth.each do |day_of_the_month| | |
= label_tag "event_repeats_monthly_each_days_of_the_month_#{day_of_the_month}", day_of_the_month, :class => 'checkbox inline' do | |
= check_box_tag "event[repeats_monthly_each_days_of_the_month][#{day_of_the_month}]", day_of_the_month, f.object.repeats_monthly_each_days_of_the_month.include?(day_of_the_month), {:name => "event[repeats_monthly_each_days_of_the_month][]"} | |
= day_of_the_month | |
= hidden_field_tag "event[repeats_monthly_each_days_of_the_month][]", "" | |
#event_repeats_monthly_on.control-group | |
%label.control-label On the | |
.controls | |
- Event::Ordinals.each_with_index do |ordinal,index| | |
= label_tag "event_repeats_monthly_on_ordinals_#{ordinal}", ordinal, :class => 'checkbox inline' do | |
= check_box_tag "event[repeats_monthly_on_ordinals][#{ordinal}]", ordinal, f.object.repeats_monthly_on_ordinals.include?(ordinal), {:name => "event[repeats_monthly_on_ordinals][]"} | |
= Event::HumanOrdinals[index] | |
= hidden_field_tag "event[repeats_monthly_on_ordinals][]", "" | |
%hr | |
- Event::DaysOfTheWeek.each do |day_of_the_week| | |
= label_tag "event_repeats_monthly_on_days_of_the_week_#{day_of_the_week}", day_of_the_week.humanize, :class => 'checkbox inline' do | |
= check_box_tag "event[repeats_monthly_on_days_of_the_week][#{day_of_the_week}]", day_of_the_week, f.object.repeats_monthly_on_days_of_the_week.include?(day_of_the_week), {:name => "event[repeats_monthly_on_days_of_the_week][]"} | |
= day_of_the_week.humanize | |
= hidden_field_tag "event[repeats_monthly_on_days_of_the_week][]", "" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%fieldset{ id: 'repeats_weekly_options', class: 'event_option'} | |
= f.number_field :repeats_every_n_weeks | |
.control-group | |
%label.control-label Each | |
.controls | |
- Event::DaysOfTheWeek.each do |day_of_the_week| | |
= label_tag "event_repeats_weekly_each_days_of_the_week_#{day_of_the_week}", day_of_the_week.humanize, :class => 'checkbox inline' do | |
= check_box_tag "event[repeats_weekly_each_days_of_the_week][#{day_of_the_week}]", day_of_the_week, f.object.repeats_weekly_each_days_of_the_week.include?(day_of_the_week), {:name => "event[repeats_weekly_each_days_of_the_week][]"} | |
= day_of_the_week.humanize | |
= hidden_field_tag "event[repeats_weekly_each_days_of_the_week][]", "" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%fieldset{ id: 'repeats_yearly_options', class: 'event_option'} | |
= f.number_field :repeats_every_n_years | |
.control-group | |
%label.control-label Each | |
.controls | |
- Event::MonthsOfTheYear.each do |month_of_the_year| | |
= label_tag "event_repeats_yearly_each_months_of_the_year_#{month_of_the_year}", month_of_the_year.humanize, :class => 'checkbox inline' do | |
= check_box_tag "event[repeats_yearly_each_months_of_the_year][#{month_of_the_year}]", month_of_the_year, f.object.repeats_yearly_each_months_of_the_year.include?(month_of_the_year), {:name => "event[repeats_yearly_each_months_of_the_year][]"} | |
= month_of_the_year.humanize | |
= hidden_field_tag "event[repeats_yearly_each_months_of_the_year][]", "" | |
= f.check_box :repeats_yearly_on | |
#event_repeats_yearly_on_options.control-group | |
%label.control-label On the | |
.controls | |
- Event::Ordinals.each_with_index do |ordinal,index| | |
= label_tag "event_repeats_yearly_on_ordinals_#{ordinal}", ordinal, :class => 'checkbox inline' do | |
= check_box_tag "event[repeats_yearly_on_ordinals][#{ordinal}]", ordinal, f.object.repeats_yearly_on_ordinals.include?(ordinal), {:name => "event[repeats_yearly_on_ordinals][]"} | |
= Event::HumanOrdinals[index] | |
= hidden_field_tag "event[repeats_yearly_on_ordinals][]", "" | |
%hr | |
- Event::DaysOfTheWeek.each do |day_of_the_week| | |
= label_tag "event_repeats_yearly_on_days_of_the_week_#{day_of_the_week}", day_of_the_week.humanize, :class => 'checkbox inline' do | |
= check_box_tag "event[repeats_yearly_on_days_of_the_week][#{day_of_the_week}]", day_of_the_week, f.object.repeats_yearly_on_days_of_the_week.include?(day_of_the_week), {:name => "event[repeats_yearly_on_days_of_the_week][]"} | |
= day_of_the_week.humanize | |
= hidden_field_tag "event[repeats_yearly_on_days_of_the_week][]", "" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#calendar{:style => 'margin:1em 0;'} | |
- content_for :last_javascripts do | |
:javascript | |
$('#calendar').fullCalendar({ | |
eventSources: [ | |
// your event source | |
{ | |
url: '/event_instances.json', | |
data: { | |
custom_param1: 'something', | |
custom_param2: 'somethingelse' | |
}, | |
error: function() { | |
alert('there was an error while fetching events!'); | |
} | |
} | |
// any other sources... | |
] | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Event < ActiveRecord::Base | |
include IceCubeMethods | |
# My custom attributes. Modify to suite your needs. | |
# attr_accessible :description, :name, :host_id, :location_id | |
# validates :name, :presence => true | |
# validates :host_id, :presence => true | |
# validates :location_id, :presence => true | |
# belongs_to :host, :class_name => 'Place' | |
# belongs_to :location, :class_name => 'Place' | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class EventInstance | |
include ActiveModel::AttributeMethods | |
attr_accessor :title, :start, :end, :allDay, :event_id | |
def self.occurrences_between(begin_date,end_date) | |
# Using Squeel | |
# line 1 = Event doesn't repeat, but ends in window | |
# line 2 = Event doesn't repeat, but starts in window | |
# line 2 = Event doesn't repeat, but starts before and ends after | |
# line 4 = Event starts before our end date and repeats until a certain point of time, and that point of time after our begin date | |
# line 5 = Event repeats indefinitely, then all we care about is that it has started at somepoint in the last | |
results = Event.where{ | |
( | |
(repeats == 'never') & | |
(from_date >= begin_date) & | |
(from_date <= end_date) | |
) | ( | |
(repeats == 'never') & | |
(to_date >= begin_date) & | |
(to_date <= end_date) | |
) | ( | |
(repeats == 'never') & | |
(from_date <= begin_date) & | |
(to_date >= end_date) | |
) | ( | |
(repeats != 'never') & | |
(from_date <= end_date) & | |
(repeat_ends == 'on') & | |
(repeat_ends_on >= begin_date) | |
) | ( | |
(repeats != 'never') & | |
(repeat_ends == 'never') & | |
(from_date <= end_date) | |
) | |
} | |
results.map { |event| | |
event.schedule.occurrences_between(begin_date,end_date).map { |date| | |
i = EventInstance.new() | |
i.title = event.name | |
i.start = date | |
i.end = date + event.duration | |
i.allDay = event.is_all_day | |
i.event_id = event.id | |
i | |
} | |
}.flatten.sort! {|x,y| x.start <=> y.start } | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class EventInstancesController < ApplicationController | |
# GET /events | |
# GET /events.json | |
def index | |
@event_instances = EventInstance.occurrences_between(Date.parse('2013-01-01'),Date.parse('2013-04-30')) | |
respond_to do |format| | |
format.html # index.html.erb | |
format.json { render json: @event_instances } | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Add these two gems | |
gem 'ice_cube', '0.9.3' | |
gem 'squeel', '1.0.16' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module IceCubeMethods | |
def self.included(base) | |
base.send :attr_accessible, :from_date | |
base.send :attr_accessible, :from_time | |
base.send :attr_accessible, :to_date | |
base.send :attr_accessible, :to_time | |
base.send :attr_accessible, :is_all_day | |
base.send :attr_accessible, :repeat_ends | |
base.send :attr_accessible, :repeat_ends_on | |
base.send :attr_accessible, :repeats | |
base.send :attr_accessible, :repeats_every_n_days | |
base.send :attr_accessible, :repeats_every_n_weeks | |
base.send :attr_accessible, :repeats_weekly_each_days_of_the_week | |
base.send :attr_accessible, :repeats_every_n_months | |
base.send :attr_accessible, :repeats_monthly | |
base.send :attr_accessible, :repeats_monthly_each_days_of_the_month | |
base.send :attr_accessible, :repeats_monthly_on_days_of_the_week | |
base.send :attr_accessible, :repeats_monthly_on_ordinals | |
base.send :attr_accessible, :repeats_every_n_years | |
base.send :attr_accessible, :repeats_yearly_each_months_of_the_year | |
base.send :attr_accessible, :repeats_yearly_on | |
base.send :attr_accessible, :repeats_yearly_on_days_of_the_week | |
base.send :attr_accessible, :repeats_yearly_on_ordinals | |
base.send :attr_accessible, :time_zone | |
base.send :validates, :repeats, :presence => true | |
base.send :validates, :repeats_every_n_days, :presence => true, :if => lambda { |e| e.repeats == "daily" } | |
base.send :validates, :repeats_every_n_weeks, :presence => true, :if => lambda { |e| e.repeats == "weekly" } | |
base.send :validate, :must_have_at_least_one_repeats_weekly_each_days_of_the_week, :if => lambda { |e| e.repeats == "weekly" } | |
base.send :validates, :repeats_every_n_months, :presence => true, :if => lambda { |e| e.repeats == "monthly" } | |
base.send :validates, :repeats_monthly, :presence => true, :if => lambda { |e| e.repeats == "monthly" } | |
base.send :validate, :must_have_at_least_one_repeats_monthly_each_days_of_the_month, :if => lambda { |e| e.repeats == "monthly" && e.repeats_monthly == 'each' } | |
base.send :validate, :must_have_at_least_one_repeats_monthly_on_ordinals, :if => lambda { |e| e.repeats == "monthly" && e.repeats_monthly == 'on' } | |
base.send :validate, :must_have_at_least_one_repeats_monthly_on_days_of_the_week, :if => lambda { |e| e.repeats == "monthly" && e.repeats_monthly == 'on' } | |
base.send :validates, :repeats_every_n_years, :presence => true, :if => lambda { |e| e.repeats == "yearly" } | |
base.send :validate, :must_have_at_least_one_repeats_yearly_each_months_of_the_year, :if => lambda { |e| e.repeats == "yearly" } | |
base.send :validate, :must_have_at_least_one_repeats_yearly_on_ordinals, :if => lambda { |e| e.repeats == "yearly" && e.repeats_yearly_on } | |
base.send :validate, :must_have_at_least_one_repeats_yearly_on_days_of_the_week, :if => lambda { |e| e.repeats == "yearly" && e.repeats_yearly_on } | |
base.send :validate, :from_must_come_before_to | |
end | |
RepeatsOptions = ['never','daily','weekly','monthly','yearly'] | |
RepeatEndsOptions = ['never','on'] | |
RepeatMonthlyOptions = ['each','on'] | |
DaysOfTheWeek = %w[sunday monday tuesday wednesday thursday friday saturday] | |
DaysOfTheMonth = (1..31).to_a | |
Ordinals = [1,2,3,4,-1] | |
HumanOrdinals = ['first','second','third','fourth','last'] | |
MonthsOfTheYear = %w[january february march april may june july august september october november december] | |
def repeats_weekly_each_days_of_the_week=(repeats_weekly_each_days_of_the_week) | |
self.repeats_weekly_each_days_of_the_week_mask = (repeats_weekly_each_days_of_the_week & DaysOfTheWeek).map { |r| 2**DaysOfTheWeek.index(r) }.inject(0, :+) | |
end | |
def repeats_weekly_each_days_of_the_week | |
DaysOfTheWeek.reject do |r| | |
((repeats_weekly_each_days_of_the_week_mask || 0) & 2**DaysOfTheWeek.index(r)).zero? | |
end | |
end | |
def repeats_monthly_each_days_of_the_month=(repeats_monthly_each_days_of_the_month) | |
repeats_monthly_each_days_of_the_month.map!{|d| d.to_i} # They come in as strings, but our array is full of integers | |
self.repeats_monthly_each_days_of_the_month_mask = (repeats_monthly_each_days_of_the_month & DaysOfTheMonth).map { |r| 2**DaysOfTheMonth.index(r) }.inject(0, :+) | |
end | |
def repeats_monthly_each_days_of_the_month | |
DaysOfTheMonth.reject do |r| | |
((repeats_monthly_each_days_of_the_month_mask || 0) & 2**DaysOfTheMonth.index(r)).zero? | |
end | |
end | |
def repeats_monthly_on_ordinals=(repeats_monthly_on_ordinals) | |
repeats_monthly_on_ordinals.map!{|o| o.to_i} # They come in as strings, but our array is full of integers | |
self.repeats_monthly_on_ordinals_mask = (repeats_monthly_on_ordinals & Ordinals).map { |r| 2**Ordinals.index(r) }.inject(0, :+) | |
end | |
def repeats_monthly_on_ordinals | |
Ordinals.reject do |r| | |
((repeats_monthly_on_ordinals_mask || 0) & 2**Ordinals.index(r)).zero? | |
end | |
end | |
def repeats_monthly_on_days_of_the_week=(repeats_monthly_on_days_of_the_week) | |
self.repeats_monthly_on_days_of_the_week_mask = (repeats_monthly_on_days_of_the_week & DaysOfTheWeek).map { |r| 2**DaysOfTheWeek.index(r) }.inject(0, :+) | |
end | |
def repeats_monthly_on_days_of_the_week | |
DaysOfTheWeek.reject do |r| | |
((repeats_monthly_on_days_of_the_week_mask || 0) & 2**DaysOfTheWeek.index(r)).zero? | |
end | |
end | |
def repeats_yearly_each_months_of_the_year=(repeats_yearly_each_months_of_the_year) | |
self.repeats_yearly_each_months_of_the_year_mask = (repeats_yearly_each_months_of_the_year & MonthsOfTheYear).map { |r| 2**MonthsOfTheYear.index(r) }.inject(0, :+) | |
end | |
def repeats_yearly_each_months_of_the_year | |
MonthsOfTheYear.reject do |r| | |
((repeats_yearly_each_months_of_the_year_mask || 0) & 2**MonthsOfTheYear.index(r)).zero? | |
end | |
end | |
def repeats_yearly_on_ordinals=(repeats_yearly_on_ordinals) | |
repeats_yearly_on_ordinals.map!{|o| o.to_i} # They come in as strings, but our array is full of integers | |
self.repeats_yearly_on_ordinals_mask = (repeats_yearly_on_ordinals & Ordinals).map { |r| 2**Ordinals.index(r) }.inject(0, :+) | |
end | |
def repeats_yearly_on_ordinals | |
Ordinals.reject do |r| | |
((repeats_yearly_on_ordinals_mask || 0) & 2**Ordinals.index(r)).zero? | |
end | |
end | |
def repeats_yearly_on_days_of_the_week=(repeats_yearly_on_days_of_the_week) | |
self.repeats_yearly_on_days_of_the_week_mask = (repeats_yearly_on_days_of_the_week & DaysOfTheWeek).map { |r| 2**DaysOfTheWeek.index(r) }.inject(0, :+) | |
end | |
def repeats_yearly_on_days_of_the_week | |
DaysOfTheWeek.reject do |r| | |
((repeats_yearly_on_days_of_the_week_mask || 0) & 2**DaysOfTheWeek.index(r)).zero? | |
end | |
end | |
def from | |
if is_all_day | |
ActiveSupport::TimeZone[time_zone].parse(from_date.to_datetime.strftime('%Y-%m-%d')).beginning_of_day | |
else | |
ActiveSupport::TimeZone[time_zone].parse(from_date.to_datetime.strftime('%Y-%m-%d')).beginning_of_day + from_time.seconds_since_midnight | |
end | |
end | |
def to | |
if is_all_day | |
ActiveSupport::TimeZone[time_zone].parse(to_date.to_datetime.strftime('%Y-%m-%d')).end_of_day | |
else | |
ActiveSupport::TimeZone[time_zone].parse(to_date.to_datetime.strftime('%Y-%m-%d')).beginning_of_day + to_time.seconds_since_midnight | |
end | |
end | |
def duration | |
d = to - from - 1 | |
end | |
def schedule(starts_at = nil, ends_at = nil) | |
starts_at ||= from | |
ends_at ||= to | |
s = IceCube::Schedule.new(starts_at, :ends_time => ends_at) | |
case repeats | |
when 'never' | |
s.add_recurrence_time(starts_at) | |
when 'daily' | |
s.add_recurrence_rule IceCube::Rule.daily(repeats_every_n_days) | |
when 'weekly' | |
days = repeats_weekly_each_days_of_the_week.map {|d| d.to_sym } | |
s.add_recurrence_rule IceCube::Rule.weekly(repeats_every_n_weeks).day(*days) | |
when 'monthly' | |
case repeats_monthly | |
when 'each' | |
s.add_recurrence_rule IceCube::Rule.monthly(repeats_every_n_months).day_of_month(*repeats_monthly_each_days_of_the_month) | |
when 'on' | |
h = {} | |
repeats_monthly_on_days_of_the_week.each do |day_of_the_week| | |
h[day_of_the_week.to_sym] = repeats_monthly_on_ordinals | |
end | |
s.add_recurrence_rule IceCube::Rule.monthly(repeats_every_n_months).day_of_week(h) | |
end | |
when 'yearly' | |
if repeats_yearly_on | |
h = {} | |
repeats_yearly_on_days_of_the_week.each do |day_of_the_week| | |
h[day_of_the_week.to_sym] = repeats_yearly_on_ordinals | |
end | |
months = repeats_yearly_each_months_of_the_year.map {|m| m.to_sym } | |
s.add_recurrence_rule IceCube::Rule.yearly(repeats_every_n_years).month_of_year(*months).day_of_week(h) | |
else | |
months = repeats_yearly_each_months_of_the_year.map {|m| m.to_sym } | |
s.add_recurrence_rule IceCube::Rule.yearly(repeats_every_n_years).month_of_year(*months) | |
end | |
end | |
return s | |
end | |
private | |
def must_have_at_least_one_repeats_weekly_each_days_of_the_week | |
if repeats_weekly_each_days_of_the_week.empty? | |
errors.add(:base, "You must have at least one repeats weekly each days of the week") | |
end | |
end | |
def must_have_at_least_one_repeats_monthly_each_days_of_the_month | |
if repeats_monthly_each_days_of_the_month.empty? | |
errors.add(:base, "You must have at least one repeats monthly each days of the month") | |
end | |
end | |
def must_have_at_least_one_repeats_monthly_on_ordinals | |
if repeats_monthly_on_ordinals.empty? | |
errors.add(:base, "You must have at least one repeats monthly on ordinals") | |
end | |
end | |
def must_have_at_least_one_repeats_monthly_on_days_of_the_week | |
if repeats_monthly_on_days_of_the_week.empty? | |
errors.add(:base, "You must have at least one repeats monthly on days of the week") | |
end | |
end | |
def must_have_at_least_one_repeats_yearly_each_months_of_the_year | |
if repeats_yearly_each_months_of_the_year.empty? | |
errors.add(:base, "You must have at least one repeats yearly each months of the year") | |
end | |
end | |
def must_have_at_least_one_repeats_yearly_on_ordinals | |
if repeats_yearly_on_ordinals.empty? | |
errors.add(:base, "You must have at least one repeats yearly on ordinals") | |
end | |
end | |
def must_have_at_least_one_repeats_yearly_on_days_of_the_week | |
if repeats_yearly_on_days_of_the_week.empty? | |
errors.add(:base, "You must have at least one repeats yearly on days of the week") | |
end | |
end | |
def from_must_come_before_to | |
if from > to | |
errors.add(:to_date, "must come after the from date") | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class CreateEvents < ActiveRecord::Migration | |
def change | |
create_table :events do |t| | |
# My custom attributes. Modify to suite your needs. | |
# t.string :name | |
# t.text :description | |
# t.integer :location_id | |
# t.integer :host_id | |
� | |
# The core migration | |
t.boolean :is_all_day | |
t.date :from_date | |
t.time :from_time | |
t.date :to_date | |
t.time :to_time | |
t.string :repeats | |
t.integer :repeats_every_n_days | |
t.integer :repeats_every_n_weeks | |
t.integer :repeats_weekly_each_days_of_the_week_mask | |
t.integer :repeats_every_n_months | |
t.string :repeats_monthly | |
t.integer :repeats_monthly_each_days_of_the_month_mask | |
t.integer :repeats_monthly_on_ordinals_mask | |
t.integer :repeats_monthly_on_days_of_the_week_mask | |
t.integer :repeats_every_n_years | |
t.integer :repeats_yearly_each_months_of_the_year_mask | |
t.boolean :repeats_yearly_on | |
t.integer :repeats_yearly_on_ordinals_mask | |
t.integer :repeats_yearly_on_days_of_the_week_mask | |
t.string :repeat_ends | |
t.date :repeat_ends_on | |
t.string :time_zone | |
t.timestamps | |
end | |
end | |
end |
@kcollignon, @jbat, @mzaragoza: the documentation for IceCube::Schedule#new shows that the param should be :end_time and not :ends_time. However, when I changed to that, it still did not fix the repeat-ends problem. So, I worked around it by adding the following change in EventInstance#occurrences_between:
results.map { |event|
schedule_end_date = end_date
if event.repeat_ends == 'on' && event.repeat_ends_on < end_date
schedule_end_date = event.repeat_ends_on
end
event.schedule.occurrences_between(begin_date,schedule_end_date).map { |date|
...
@kleinjm, I removed the :attr_accessible
lines from IceCubeMethods
since ActiveRecord will create those by default based on the DB columns. Also, I'm using this on Rails 5, but I had to use baby_squeel since squeel doesn't support Rails 5 (baby_squeel supports Rails 4/5). To port to baby_squeel, just use Event.where.has{
in EventInstance instead of Event.where{
.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Has anyone ported this to Rails 4? Not sure how
send :attr_accessible
is supposed to work inIceCubeMethods
in Rails 4