radiant-event_map-extension 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +95 -0
- data/Rakefile +138 -0
- data/VERSION +1 -0
- data/app/controllers/event_venues_controller.rb +50 -0
- data/app/views/event_venues/_event.html.haml +20 -0
- data/app/views/event_venues/_venue.html.haml +23 -0
- data/app/views/event_venues/index.html.haml +17 -0
- data/app/views/event_venues/index.js.erb +55 -0
- data/app/views/events/_views.html.haml +11 -0
- data/config/routes.rb +8 -0
- data/cucumber.yml +1 -0
- data/db/migrate/20100311101802_lat_long.rb +20 -0
- data/db/migrate/20100311105231_get_geocodes.rb +17 -0
- data/event_map_extension.rb +19 -0
- data/features/support/env.rb +16 -0
- data/features/support/paths.rb +14 -0
- data/lib/angle_conversions.rb +9 -0
- data/lib/grid_ref.rb +279 -0
- data/lib/mappable.rb +63 -0
- data/lib/tasks/event_map_extension_tasks.rake +28 -0
- data/pkg/radiant-event_map-extension-1.0.1.gem +0 -0
- data/public/images/event_calendar/event_shadow.png +0 -0
- data/public/images/event_calendar/one_event.png +0 -0
- data/public/images/event_calendar/several_events.png +0 -0
- data/public/javascript/markerclusterer.js +735 -0
- data/public/stylesheets/sass/map.sass +11 -0
- data/radiant-event_map-extension.gemspec +79 -0
- data/spec/lib/grid_ref_spec.rb +90 -0
- data/spec/spec.opts +6 -0
- data/spec/spec_helper.rb +36 -0
- metadata +140 -0
data/README.md
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
# Event Map Extension for Radiant
|
2
|
+
|
3
|
+
This extension adds mapping to the [event_calendar](http://github.com/radiant/radiant-event-calendar-extension). It will geocode your events automatically based on the address of the venue, or you can supply a postal code, UK postcode or grid reference for greater precision.
|
4
|
+
|
5
|
+
Events can be displayed on a google map and you can create links to bing or google maps that display the location of each event.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Should be straightforward:
|
10
|
+
|
11
|
+
script/extension install event_map
|
12
|
+
|
13
|
+
or as a gem:
|
14
|
+
|
15
|
+
gem install radiant-event_map-extension
|
16
|
+
|
17
|
+
## Requirements
|
18
|
+
|
19
|
+
* [event_calendar](http://github.com/radiant/radiant-event-calendar-extension) extension
|
20
|
+
* [layouts](http://github.com/squaretalent/radiant-layouts-extension) or [share_layouts](http://github.com/radiant/radiant-share-layouts-extension) extension
|
21
|
+
* [geokit](http://geokit.rubyforge.org/) gem
|
22
|
+
|
23
|
+
## Configuration
|
24
|
+
|
25
|
+
There is one required config setting:
|
26
|
+
|
27
|
+
* `event_map.layout` is the name of the layout used by the controller
|
28
|
+
|
29
|
+
## Basic Usage
|
30
|
+
|
31
|
+
### Linking to maps
|
32
|
+
|
33
|
+
We override the `url` method of EventVenue to return a map link if no other url is defined. The format of those links is determined by the link template stored in the config setting `event_map.link_format`. The markers :lat, :lng and :title will be replaced with the the correct value for each event venue.
|
34
|
+
|
35
|
+
There are also two shortcuts:
|
36
|
+
|
37
|
+
* 'google' is the default and equivalent to `http://maps.google.com/maps?q=:lat+:lng+(:title)` and will drop a pin on a google map.
|
38
|
+
* 'bing' is equivalent to `http://www.bing.com/maps/?v=2&cp=:lat~:lng&rtp=~pos.:lat_:lng_:title&lvl=15&sty=s&eo=0`, which will display a 1:25000 ordnance survey map (if you're in the UK) with a destination flag at your chosen point.
|
39
|
+
|
40
|
+
### Displaying a map page
|
41
|
+
|
42
|
+
Create a layout that includes a `map_canvas` div and these page parts:
|
43
|
+
|
44
|
+
* `map_js` is required. It brings in the javascripts (and can be used in the header or at the end of the page as you prefer)
|
45
|
+
* `title` is the page title and can also be shown with `r:title`
|
46
|
+
* `faceting` here only gives the option to remove any date filters that have been applied. If you add the `taggable_events` extension it gets more useful.
|
47
|
+
|
48
|
+
Here's a starting point:
|
49
|
+
|
50
|
+
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
|
51
|
+
<head>
|
52
|
+
<title><r:title /></title>
|
53
|
+
<r:content part="map_js" />
|
54
|
+
</head>
|
55
|
+
<body>
|
56
|
+
<h1 id="pagetitle"><r:title /></h1>
|
57
|
+
<r:content part="faceting" />
|
58
|
+
<div id="map_canvas" style="width: 600px; height 400px;"></div>
|
59
|
+
</body>
|
60
|
+
</html>
|
61
|
+
|
62
|
+
Make sure that `Radiant::Config['event_map.layout']` matches exactly the _name_ of this layout.
|
63
|
+
|
64
|
+
### javascript compatibility
|
65
|
+
|
66
|
+
The map javascript is generated by the EventVenuesController using `app/views/event_venues/index.js.erb`. It provides a `build_map_and_markers` method and the minimal jQuery hook required to populate #map_canvas when the DOM loads.
|
67
|
+
|
68
|
+
If you're not using jQuery you should find it straightforward to call `build_map_and_markers(div element)` from another script, and in that case you don't have to use our naming scheme either.
|
69
|
+
|
70
|
+
### JSON interface
|
71
|
+
|
72
|
+
If you don't want to use the included scripts, you can skip that whole mechanism and work with the event data instead. EventVenuesController provides a simple JSON interface. Usually it's at /map and looks for addresses like this:
|
73
|
+
|
74
|
+
/map everything
|
75
|
+
/map/2010 events in 2010
|
76
|
+
/map/2010/12/ events in December 2010
|
77
|
+
/map/2010/12/12 events on 12 December 2010
|
78
|
+
|
79
|
+
If you're using `taggable_events` then we also inherit the tag-faceting interface here.
|
80
|
+
|
81
|
+
The data returned looks like this:
|
82
|
+
|
83
|
+
{
|
84
|
+
|
85
|
+
}
|
86
|
+
|
87
|
+
## Bugs and features
|
88
|
+
|
89
|
+
[Github issues](http://github.com/spanner/radiant-event_map-extension/issues) please, or for little things an email or github message is fine.
|
90
|
+
|
91
|
+
## Author & Copyright
|
92
|
+
|
93
|
+
Copyright 2008-2010 Will at spanner.org.
|
94
|
+
|
95
|
+
Released under the same terms as Radiant and/or Rails.
|
data/Rakefile
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
begin
|
2
|
+
require 'jeweler'
|
3
|
+
Jeweler::Tasks.new do |gem|
|
4
|
+
gem.name = "radiant-event_map-extension"
|
5
|
+
gem.summary = %Q{Google mapping for events in the radiant CMS}
|
6
|
+
gem.description = %Q{Further extends the event_calendar extension to allow easy google mapping with automatic geolocation based on event venues}
|
7
|
+
gem.email = "will@spanner.org"
|
8
|
+
gem.homepage = "http://github.com/radiant/radiant-event_map-extension"
|
9
|
+
gem.authors = ["spanner"]
|
10
|
+
gem.add_dependency "geokit"
|
11
|
+
gem.add_dependency "radiant", ">= 0.9.0"
|
12
|
+
gem.add_dependency "radiant-event_calendar-extension"
|
13
|
+
end
|
14
|
+
rescue LoadError
|
15
|
+
puts "Jeweler (or a dependency) not available. This is only required if you plan to package event_map as a gem."
|
16
|
+
end
|
17
|
+
|
18
|
+
# In rails 1.2, plugins aren't available in the path until they're loaded.
|
19
|
+
# Check to see if the rspec plugin is installed first and require
|
20
|
+
# it if it is. If not, use the gem version.
|
21
|
+
|
22
|
+
# Determine where the RSpec plugin is by loading the boot
|
23
|
+
unless defined? RADIANT_ROOT
|
24
|
+
ENV["RAILS_ENV"] = "test"
|
25
|
+
case
|
26
|
+
when ENV["RADIANT_ENV_FILE"]
|
27
|
+
require File.dirname(ENV["RADIANT_ENV_FILE"]) + "/boot"
|
28
|
+
when File.dirname(__FILE__) =~ %r{vendor/radiant/vendor/extensions}
|
29
|
+
require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../")}/config/boot"
|
30
|
+
else
|
31
|
+
require "#{File.expand_path(File.dirname(__FILE__) + "/../../../")}/config/boot"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
require 'rake'
|
36
|
+
require 'rake/rdoctask'
|
37
|
+
require 'rake/testtask'
|
38
|
+
|
39
|
+
rspec_base = File.expand_path(RADIANT_ROOT + '/vendor/plugins/rspec/lib')
|
40
|
+
$LOAD_PATH.unshift(rspec_base) if File.exist?(rspec_base)
|
41
|
+
require 'spec/rake/spectask'
|
42
|
+
require 'cucumber'
|
43
|
+
require 'cucumber/rake/task'
|
44
|
+
|
45
|
+
# Cleanup the RADIANT_ROOT constant so specs will load the environment
|
46
|
+
Object.send(:remove_const, :RADIANT_ROOT)
|
47
|
+
|
48
|
+
extension_root = File.expand_path(File.dirname(__FILE__))
|
49
|
+
|
50
|
+
task :default => :spec
|
51
|
+
task :stats => "spec:statsetup"
|
52
|
+
|
53
|
+
desc "Run all specs in spec directory"
|
54
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
55
|
+
t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
|
56
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
57
|
+
end
|
58
|
+
|
59
|
+
task :features => 'spec:integration'
|
60
|
+
|
61
|
+
namespace :spec do
|
62
|
+
desc "Run all specs in spec directory with RCov"
|
63
|
+
Spec::Rake::SpecTask.new(:rcov) do |t|
|
64
|
+
t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
|
65
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
66
|
+
t.rcov = true
|
67
|
+
t.rcov_opts = ['--exclude', 'spec', '--rails']
|
68
|
+
end
|
69
|
+
|
70
|
+
desc "Print Specdoc for all specs"
|
71
|
+
Spec::Rake::SpecTask.new(:doc) do |t|
|
72
|
+
t.spec_opts = ["--format", "specdoc", "--dry-run"]
|
73
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
74
|
+
end
|
75
|
+
|
76
|
+
[:models, :controllers, :views, :helpers].each do |sub|
|
77
|
+
desc "Run the specs under spec/#{sub}"
|
78
|
+
Spec::Rake::SpecTask.new(sub) do |t|
|
79
|
+
t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
|
80
|
+
t.spec_files = FileList["spec/#{sub}/**/*_spec.rb"]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
desc "Run the Cucumber features"
|
85
|
+
Cucumber::Rake::Task.new(:integration) do |t|
|
86
|
+
t.fork = true
|
87
|
+
t.cucumber_opts = ['--format', (ENV['CUCUMBER_FORMAT'] || 'pretty')]
|
88
|
+
# t.feature_pattern = "#{extension_root}/features/**/*.feature"
|
89
|
+
t.profile = "default"
|
90
|
+
end
|
91
|
+
|
92
|
+
# Setup specs for stats
|
93
|
+
task :statsetup do
|
94
|
+
require 'code_statistics'
|
95
|
+
::STATS_DIRECTORIES << %w(Model\ specs spec/models)
|
96
|
+
::STATS_DIRECTORIES << %w(View\ specs spec/views)
|
97
|
+
::STATS_DIRECTORIES << %w(Controller\ specs spec/controllers)
|
98
|
+
::STATS_DIRECTORIES << %w(Helper\ specs spec/views)
|
99
|
+
::CodeStatistics::TEST_TYPES << "Model specs"
|
100
|
+
::CodeStatistics::TEST_TYPES << "View specs"
|
101
|
+
::CodeStatistics::TEST_TYPES << "Controller specs"
|
102
|
+
::CodeStatistics::TEST_TYPES << "Helper specs"
|
103
|
+
::STATS_DIRECTORIES.delete_if {|a| a[0] =~ /test/}
|
104
|
+
end
|
105
|
+
|
106
|
+
namespace :db do
|
107
|
+
namespace :fixtures do
|
108
|
+
desc "Load fixtures (from spec/fixtures) into the current environment's database. Load specific fixtures using FIXTURES=x,y"
|
109
|
+
task :load => :environment do
|
110
|
+
require 'active_record/fixtures'
|
111
|
+
ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym)
|
112
|
+
(ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir.glob(File.join(RAILS_ROOT, 'spec', 'fixtures', '*.{yml,csv}'))).each do |fixture_file|
|
113
|
+
Fixtures.create_fixtures('spec/fixtures', File.basename(fixture_file, '.*'))
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
desc 'Generate documentation for the event_map extension.'
|
121
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
122
|
+
rdoc.rdoc_dir = 'rdoc'
|
123
|
+
rdoc.title = 'EventMapExtension'
|
124
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
125
|
+
rdoc.rdoc_files.include('README')
|
126
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
127
|
+
end
|
128
|
+
|
129
|
+
# For extensions that are in transition
|
130
|
+
desc 'Test the event_map extension.'
|
131
|
+
Rake::TestTask.new(:test) do |t|
|
132
|
+
t.libs << 'lib'
|
133
|
+
t.pattern = 'test/**/*_test.rb'
|
134
|
+
t.verbose = true
|
135
|
+
end
|
136
|
+
|
137
|
+
# Load any custom rakefiles for extension
|
138
|
+
Dir[File.dirname(__FILE__) + '/tasks/*.rake'].sort.each { |f| require f }
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.1.0
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# We inherit from EventsController to share subsetting functionality
|
2
|
+
# All we do here is organise that information by venue.
|
3
|
+
|
4
|
+
class EventVenuesController < EventsController
|
5
|
+
helper_method :venues, :events_at_venue
|
6
|
+
radiant_layout { |controller| controller.layout_for :event_map }
|
7
|
+
|
8
|
+
def index
|
9
|
+
respond_to do |format|
|
10
|
+
format.html { }
|
11
|
+
format.js {
|
12
|
+
render :layout => false
|
13
|
+
}
|
14
|
+
format.json {
|
15
|
+
render :json => venue_events.to_json
|
16
|
+
}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# event_finder is defined in EventsController
|
21
|
+
|
22
|
+
def events
|
23
|
+
@events ||= all_events
|
24
|
+
end
|
25
|
+
|
26
|
+
def venues
|
27
|
+
@venues ||= events.map(&:event_venue).compact.uniq
|
28
|
+
end
|
29
|
+
|
30
|
+
# events are stashed in venue buckets to avoid returning to the database
|
31
|
+
|
32
|
+
def events_at_venue(venue)
|
33
|
+
venue_events[venue.id]
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
def venue_events
|
39
|
+
return @venue_events if @venue_events
|
40
|
+
@venue_events = {}
|
41
|
+
events.each do |e|
|
42
|
+
if e.event_venue
|
43
|
+
@venue_events[e.event_venue.id] ||= []
|
44
|
+
@venue_events[e.event_venue.id].push(e)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
@venue_events
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
- without_title ||= false
|
2
|
+
|
3
|
+
- if event
|
4
|
+
.map_event
|
5
|
+
- unless without_title
|
6
|
+
%h3.event
|
7
|
+
= link_to event.title, event.url
|
8
|
+
|
9
|
+
%p.date
|
10
|
+
%strong
|
11
|
+
= event.summarize_period
|
12
|
+
- if event.event_venue
|
13
|
+
at
|
14
|
+
= link_to event.event_venue.title, event.event_venue.url
|
15
|
+
- else
|
16
|
+
at
|
17
|
+
= event.location
|
18
|
+
|
19
|
+
%p.description
|
20
|
+
= event.short_description
|
@@ -0,0 +1,23 @@
|
|
1
|
+
- if venue
|
2
|
+
- if events = events_at_venue(venue)
|
3
|
+
.map_venue
|
4
|
+
- if events.length == 1
|
5
|
+
= render :partial => 'event', :object => events.first
|
6
|
+
- else
|
7
|
+
%h3
|
8
|
+
Events at
|
9
|
+
= link_to venue.title, venue.url
|
10
|
+
%ul
|
11
|
+
- remainder = events.slice!(4, 10000)
|
12
|
+
- events.each do |event|
|
13
|
+
%li
|
14
|
+
%strong
|
15
|
+
= link_to event.title, event.url
|
16
|
+
on
|
17
|
+
= event.date
|
18
|
+
- if remainder && remainder.any?
|
19
|
+
%li
|
20
|
+
and
|
21
|
+
= remainder.length
|
22
|
+
more events...
|
23
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
- content_for :title do
|
2
|
+
Events
|
3
|
+
= list_description
|
4
|
+
|
5
|
+
- content_for :faceting do
|
6
|
+
= render :partial => 'events/faceting'
|
7
|
+
|
8
|
+
- content_for :map_js do
|
9
|
+
%script{:src => "http://maps.google.com/maps/api/js?sensor=false"}
|
10
|
+
%script{:src => "#{url_for(calendar_parameters.merge(:format => :js))}"}
|
11
|
+
|
12
|
+
/ deprecated older syntax probably unknown to anyone but me
|
13
|
+
- content_for :head do
|
14
|
+
%script{:src => "http://maps.google.com/maps/api/js?sensor=false"}
|
15
|
+
%script{:src => "#{url_for(calendar_parameters.merge(:format => :js))}"}
|
16
|
+
|
17
|
+
= render :partial => 'events/other_page_parts'
|
@@ -0,0 +1,55 @@
|
|
1
|
+
if(typeof jQuery == 'function') {
|
2
|
+
jQuery.fn.populate_map = function() {
|
3
|
+
this.each(function() { build_map_and_markers(this); });
|
4
|
+
};
|
5
|
+
|
6
|
+
jQuery(function() {
|
7
|
+
jQuery("#map_canvas").populate_map();
|
8
|
+
});
|
9
|
+
}
|
10
|
+
|
11
|
+
function build_map_and_markers(element) {
|
12
|
+
if (element != null) {
|
13
|
+
var map = new google.maps.Map(element, {mapTypeId: google.maps.MapTypeId.ROADMAP});
|
14
|
+
var bounds = new google.maps.LatLngBounds();
|
15
|
+
var one_icon = new google.maps.MarkerImage('/images/event_calendar/one_event.png',
|
16
|
+
new google.maps.Size(26,45),
|
17
|
+
new google.maps.Point(0,0),
|
18
|
+
new google.maps.Point(7, 45));
|
19
|
+
var several_icon = new google.maps.MarkerImage('/images/event_calendar/several_events.png',
|
20
|
+
new google.maps.Size(26,45),
|
21
|
+
new google.maps.Point(0,0),
|
22
|
+
new google.maps.Point(9, 45));
|
23
|
+
var one_shadow = new google.maps.MarkerImage('/images/event_calendar/event_shadow.png',
|
24
|
+
new google.maps.Size(60, 44),
|
25
|
+
new google.maps.Point(0,0),
|
26
|
+
new google.maps.Point(8, 45));
|
27
|
+
var several_shadow = new google.maps.MarkerImage('/images/event_calendar/event_shadow.png',
|
28
|
+
new google.maps.Size(60, 44),
|
29
|
+
new google.maps.Point(0,0),
|
30
|
+
new google.maps.Point(5, 45));
|
31
|
+
<% venues.each do |venue| %>
|
32
|
+
add_marker(map, {
|
33
|
+
title : "<%= escape_javascript(venue.title) %>",
|
34
|
+
image : <%= events_at_venue(venue).length > 1 ? "several_icon" : "one_icon" %>,
|
35
|
+
shadow : <%= events_at_venue(venue).length > 1 ? "several_shadow" : "one_shadow" %>,
|
36
|
+
position : new google.maps.LatLng("<%= venue.lat %>","<%= venue.lng %>"),
|
37
|
+
description : "<%= escape_javascript(render :partial => 'venue', :object => venue) %>"
|
38
|
+
});
|
39
|
+
bounds.extend(new google.maps.LatLng("<%= venue.lat %>","<%= venue.lng %>"));
|
40
|
+
<% end %>
|
41
|
+
map.fitBounds(bounds);
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
function add_marker (map, mark) {
|
46
|
+
var marker = new google.maps.Marker({ map : map, position : mark['position'], title : mark['title'], icon : mark['image'], shadow : mark['shadow'] });
|
47
|
+
var infowindow = new google.maps.InfoWindow({ content : mark['description'] , maxWidth : 400 });
|
48
|
+
google.maps.event.addListener(marker, 'click', function() { infowindow.open(map, marker); });
|
49
|
+
}
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
|
@@ -0,0 +1,11 @@
|
|
1
|
+
%span.calendar_views
|
2
|
+
%br
|
3
|
+
View as
|
4
|
+
= link_to("map", eventmap_url(calendar_parameters))
|
5
|
+
or
|
6
|
+
= link_to("calendar", calendar_url(calendar_parameters)) + "."
|
7
|
+
Stay up to date with
|
8
|
+
= link_to("RSS", calendar_url(calendar_parameters.merge(:format => :rss)))
|
9
|
+
or
|
10
|
+
= link_to("calendar feed", calendar_url(calendar_parameters.merge(:format => :ics, :protocol => 'webcal://', :only_path => false)))
|
11
|
+
|
data/config/routes.rb
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
ActionController::Routing::Routes.draw do |map|
|
2
|
+
map.with_options :controller => 'event_venues', :action => 'index' do |m|
|
3
|
+
m.eventmap "/map.:format"
|
4
|
+
m.eventmap_year "/map/:year.:format"
|
5
|
+
m.eventmap_month "/map/:year/:month.:format"
|
6
|
+
m.eventmap_day "/map/:year/:month/:mday.:format"
|
7
|
+
end
|
8
|
+
end
|
data/cucumber.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
default: --format progress features --tags ~@proposed,~@in_progress
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class LatLong < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
add_column :events, :lat, :string
|
4
|
+
add_column :events, :lng, :string
|
5
|
+
add_column :event_venues, :lat, :string
|
6
|
+
add_column :event_venues, :lng, :string
|
7
|
+
add_index :events, [:lat, :lng]
|
8
|
+
add_index :event_venues, [:lat, :lng]
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.down
|
13
|
+
remove_column :events, :lat
|
14
|
+
remove_column :events, :lng
|
15
|
+
remove_column :event_venues, :lat
|
16
|
+
remove_column :event_venues, :lng
|
17
|
+
remove_index :events, [:lat, :lng]
|
18
|
+
remove_index :event_venues, [:lat, :lng]
|
19
|
+
end
|
20
|
+
end
|