-
-
Save nathancolgate/4998196 to your computer and use it in GitHub Desktop.
= 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;} |
%fieldset{id: 'repeats_daily_options', class: 'event_option'} | |
= f.number_field :repeats_every_n_days |
%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][]", "" |
%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][]", "" |
%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][]", "" |
#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... | |
] | |
}); |
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 |
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 |
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 |
# Add these two gems | |
gem 'ice_cube', '0.9.3' | |
gem 'squeel', '1.0.16' |
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 |
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 |
This is totally awesome. Great work!
+1 to the repeat-ends feature not adding an exception
Has anyone made any improvements to this?
Really really great work. You saved me hours of time here. Thanks a bunch!
I'd recommend you all check out this gem, which I've used. It hides most of this complexity and adds a slick UI: https://github.com/GetJobber/recurring_select
Nice interface! Will you ever package this as a gem?
@jbat or @mzaragoza did you ever by chance get updated code to handle adding an exception to schedules? thanks
this great thank you
@nathancolgate Thanks, this really saved me a lot of time.
Has anyone ported this to Rails 4? Not sure how send :attr_accessible
is supposed to work in IceCubeMethods
in Rails 4
@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{
.
Created a Demo of this
http://rails-fullcalendar-icecube.herokuapp.com/
Github
https://github.com/mzararagoza/rails-fullcalendar-icecube
There are some problems with repeat-ends feature not adding an exception to the schedule
Can you foward me an updated module IceCubeMethods