belongs_to_city 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.textile +120 -0
- data/Rakefile +20 -0
- data/VERSION +1 -0
- data/belongs_to_city.gemspec +66 -0
- data/generators/belongs_to_city/USAGE +48 -0
- data/generators/belongs_to_city/belongs_to_city_generator.rb +67 -0
- data/generators/belongs_to_city/lib/insert_routes.rb +54 -0
- data/generators/belongs_to_city/templates/belongs_to_city_tasks.rake +27 -0
- data/generators/belongs_to_city/templates/cities.csv +2 -0
- data/generators/belongs_to_city/templates/controllers/cities_controller.rb +8 -0
- data/generators/belongs_to_city/templates/countries.csv +2 -0
- data/generators/belongs_to_city/templates/migrate/create_belongs_to_city_tables.rb +37 -0
- data/generators/belongs_to_city/templates/models/city.rb +15 -0
- data/generators/belongs_to_city/templates/models/country.rb +2 -0
- data/generators/belongs_to_city/templates/models/state.rb +3 -0
- data/generators/belongs_to_city/templates/states.csv +2 -0
- data/generators/belongs_to_city/templates/views/index.js.erb +3 -0
- data/lib/belongs_to_city.rb +56 -0
- metadata +117 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Innku
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.textile
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
h1. Belongs to city
|
2
|
+
|
3
|
+
p. Rails gem that eases the relation between your existing models and a City -> State -> Country type of database.
|
4
|
+
|
5
|
+
p. It is thought primarily to be used in a city autocomplete feature and includes the functionality to get started with the jquery autocomplete plugin.
|
6
|
+
|
7
|
+
***************************************************************************
|
8
|
+
|
9
|
+
h2. Install
|
10
|
+
|
11
|
+
bc. gem install belongs_to_city
|
12
|
+
|
13
|
+
***************************************************************************
|
14
|
+
|
15
|
+
h2. Generate the city Structure
|
16
|
+
|
17
|
+
p. First of all you need to generate the structure that includes the City, State and Country in your application.
|
18
|
+
|
19
|
+
p. You can do this with the following command
|
20
|
+
|
21
|
+
bc. script/generate belongs_to_city
|
22
|
+
|
23
|
+
p. This will generate 3 basic things. A migration file that creates the previously mentioned tables, the 3 models and the cities controller (Since you will be accesing this for the autocomplete functionality). Also it will generate the routes to access this last controller.
|
24
|
+
|
25
|
+
p. Also You can optionally give the arguments of the things you need for your application. with the following options
|
26
|
+
|
27
|
+
* tables - Generates the migration
|
28
|
+
* models - Generates the models
|
29
|
+
* controller - Generates the controller and the resource route
|
30
|
+
|
31
|
+
p. So the previous line of code is *equivalent* to:
|
32
|
+
|
33
|
+
bc. script/generate belongs_to_city tables models controller
|
34
|
+
|
35
|
+
p. *OPTIONS*
|
36
|
+
|
37
|
+
p. Optionally you can provide the following options that will further help you to generate the database and start on the autocomplete feature
|
38
|
+
|
39
|
+
p. *--include-seed* will create a rake task to seed your City based database using .csv files. For this to work you need to have your csv files stored in db/csv folder and the files should have the following format.
|
40
|
+
|
41
|
+
*countries.csv*
|
42
|
+
|
43
|
+
|*name*|
|
44
|
+
|Mexico|
|
45
|
+
|USA|
|
46
|
+
|
47
|
+
*states.csv*
|
48
|
+
|
49
|
+
|*country_id*|*name*|*abbr*|*short*|*short2*|
|
50
|
+
|1|Nuevo Leon|N.L.|NL|NLE|
|
51
|
+
|1|Jalisco|Jal.|JA|JAL|
|
52
|
+
|
53
|
+
*cities.csv*
|
54
|
+
|
55
|
+
|*state_id*|*name*|*city_name*|
|
56
|
+
|1|Monterey|Monterrey|
|
57
|
+
|2|Guadalajara|Guadalajara|
|
58
|
+
|
59
|
+
p. All that matters is that the header is present in the csv files, the order can change if you wish.
|
60
|
+
|
61
|
+
p. *--jq-autocomplete* This will generate the view ready to be used in the jq-autocomplete plugin and print out the code to be pasted in the application.js file.
|
62
|
+
|
63
|
+
p. The following command generates everything including the jq view file:
|
64
|
+
|
65
|
+
bc. script/generate belongs_to_city --include-seed --jq-autocomplete
|
66
|
+
|
67
|
+
***************************************************************************
|
68
|
+
|
69
|
+
h2. Use the City structure in your models
|
70
|
+
|
71
|
+
p. To use the city structure in your models, *include an integer city_id* column in the model you want to use it and paste the following code into the model.
|
72
|
+
|
73
|
+
bc. belongs_to_city
|
74
|
+
|
75
|
+
p. This gives you the attribute *city_name*. Each time you assign a value to this attribute, the gem will look for a city that matches the string in a 'city, state' format.
|
76
|
+
|
77
|
+
p. For example, with the given data on the csv example tables, the city monterrey would be assigned to a model given the following strings:
|
78
|
+
|
79
|
+
* Monterrey, Nuevo Leon
|
80
|
+
* Monterrey, NL
|
81
|
+
* Monterrey
|
82
|
+
* Monte
|
83
|
+
|
84
|
+
p. After the assignation, you would get a city model instance when you called _model.city_
|
85
|
+
|
86
|
+
h3. Use the City in many attributes
|
87
|
+
|
88
|
+
p. If you have a model that needs more than one relation to a city, you could also pull it off like the following example.
|
89
|
+
|
90
|
+
p. Say you have a *Travel* model that has an *origin* and a *destination*, both related to a city. First of all you need to add an *origin_id* and a *destination_id* to the Model and then use this code into the model.
|
91
|
+
|
92
|
+
bc. belongs_to_city :as => :origin
|
93
|
+
|
94
|
+
bc. belongs_to_city :as => :destination
|
95
|
+
|
96
|
+
p. The code works the same way as previously stated, but instead of a _city_name_ attribute you would have the *origin_name* and *destination_name* attributes.
|
97
|
+
|
98
|
+
h3. Validate the presence of the City
|
99
|
+
|
100
|
+
p. If your using the autocomplete to find the city, you can validate that you have a city in the following way:
|
101
|
+
|
102
|
+
bc. belongs_to_city :as => :origin, :required => true
|
103
|
+
|
104
|
+
p. This gives you the ability to handle errors more appropriately like in the following way.
|
105
|
+
|
106
|
+
bc. belongs_to_city :as => :origin, :required => true, :messages => {:on_many_matches => 'We found many cities with your request, please be more specific!, :on_no_matches => 'We didnt find any city with the data you provided'}
|
107
|
+
|
108
|
+
|
109
|
+
***************************************************************************
|
110
|
+
|
111
|
+
h2. TODO
|
112
|
+
|
113
|
+
* Generators for relation migration in the database
|
114
|
+
* Puts Jquery code to paste in application.js
|
115
|
+
* Tests
|
116
|
+
|
117
|
+
***************************************************************************
|
118
|
+
h2. Copyright
|
119
|
+
|
120
|
+
Copyright (c) 2010 Innku. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gemspec|
|
7
|
+
gemspec.name = "belongs_to_city"
|
8
|
+
gemspec.summary = "Eases integrating a city database structure with any model in rails"
|
9
|
+
gemspec.description = "Creates the basic structure to enable City structure integration with any model and eases autocomplete search"
|
10
|
+
gemspec.email = "adrian@innku.com"
|
11
|
+
gemspec.homepage = "http://github.com/adriancuadros/belongs_to_city"
|
12
|
+
gemspec.authors = ["Adrian Cuadros"]
|
13
|
+
gemspec.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
14
|
+
gemspec.add_development_dependency "searchlogic"
|
15
|
+
gemspec.add_development_dependency "fastercsv"
|
16
|
+
end
|
17
|
+
Jeweler::GemcutterTasks.new
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
20
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.6.0
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{belongs_to_city}
|
8
|
+
s.version = "0.6.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Adrian Cuadros"]
|
12
|
+
s.date = %q{2010-05-21}
|
13
|
+
s.description = %q{Creates the basic structure to enable City structure integration with any model and eases autocomplete search}
|
14
|
+
s.email = %q{adrian@innku.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.textile"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".gitignore",
|
21
|
+
"LICENSE",
|
22
|
+
"README.textile",
|
23
|
+
"Rakefile",
|
24
|
+
"VERSION",
|
25
|
+
"belongs_to_city.gemspec",
|
26
|
+
"generators/belongs_to_city/USAGE",
|
27
|
+
"generators/belongs_to_city/belongs_to_city_generator.rb",
|
28
|
+
"generators/belongs_to_city/lib/insert_routes.rb",
|
29
|
+
"generators/belongs_to_city/templates/belongs_to_city_tasks.rake",
|
30
|
+
"generators/belongs_to_city/templates/cities.csv",
|
31
|
+
"generators/belongs_to_city/templates/controllers/cities_controller.rb",
|
32
|
+
"generators/belongs_to_city/templates/countries.csv",
|
33
|
+
"generators/belongs_to_city/templates/migrate/create_belongs_to_city_tables.rb",
|
34
|
+
"generators/belongs_to_city/templates/models/city.rb",
|
35
|
+
"generators/belongs_to_city/templates/models/country.rb",
|
36
|
+
"generators/belongs_to_city/templates/models/state.rb",
|
37
|
+
"generators/belongs_to_city/templates/states.csv",
|
38
|
+
"generators/belongs_to_city/templates/views/index.js.erb",
|
39
|
+
"lib/belongs_to_city.rb"
|
40
|
+
]
|
41
|
+
s.homepage = %q{http://github.com/adriancuadros/belongs_to_city}
|
42
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
43
|
+
s.require_paths = ["lib"]
|
44
|
+
s.rubygems_version = %q{1.3.6}
|
45
|
+
s.summary = %q{Eases integrating a city database structure with any model in rails}
|
46
|
+
|
47
|
+
if s.respond_to? :specification_version then
|
48
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
49
|
+
s.specification_version = 3
|
50
|
+
|
51
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
52
|
+
s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
53
|
+
s.add_development_dependency(%q<searchlogic>, [">= 0"])
|
54
|
+
s.add_development_dependency(%q<fastercsv>, [">= 0"])
|
55
|
+
else
|
56
|
+
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
57
|
+
s.add_dependency(%q<searchlogic>, [">= 0"])
|
58
|
+
s.add_dependency(%q<fastercsv>, [">= 0"])
|
59
|
+
end
|
60
|
+
else
|
61
|
+
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
62
|
+
s.add_dependency(%q<searchlogic>, [">= 0"])
|
63
|
+
s.add_dependency(%q<fastercsv>, [">= 0"])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
@@ -0,0 +1,48 @@
|
|
1
|
+
Description:
|
2
|
+
This command will generate all the tables, models, controllers, views
|
3
|
+
and seeds needed to get started with the city autocomplete functionality.
|
4
|
+
|
5
|
+
Usage:
|
6
|
+
The default option for the generate command will create
|
7
|
+
all the files. You can optionally give the arguments of
|
8
|
+
the things you need for your application.
|
9
|
+
|
10
|
+
- tables : Will generate the migration files
|
11
|
+
- models : Will generate the models
|
12
|
+
- controller : Will generate the controller
|
13
|
+
|
14
|
+
Optionally you can include the rake task to seed your database
|
15
|
+
|
16
|
+
--include-seeds
|
17
|
+
|
18
|
+
This option will include the following rake task
|
19
|
+
|
20
|
+
rake db:seed:cities
|
21
|
+
|
22
|
+
It will generate 3 csv files (country, state, city) that you can populate
|
23
|
+
to seed your database.
|
24
|
+
|
25
|
+
Also you con optionally include the option that eases jq autocomplete
|
26
|
+
|
27
|
+
--jq-autocomplete
|
28
|
+
|
29
|
+
With these option a view is generated with the standard used for the autocomplete
|
30
|
+
|
31
|
+
If you would like to use any other plugin other than the specified, it is
|
32
|
+
recommended you format the data according to your needs.
|
33
|
+
|
34
|
+
Examples:
|
35
|
+
script/generate belongs_to_city
|
36
|
+
|
37
|
+
Will generate migration, models, controller, view and seed files
|
38
|
+
|
39
|
+
script/generate belongs_to_city models controller
|
40
|
+
|
41
|
+
Will generate models, controller and view
|
42
|
+
|
43
|
+
script/generate migration model seed
|
44
|
+
Will generate migration, models and seed
|
45
|
+
This option is recommended when you don't
|
46
|
+
want to use the jquery autocomplete plugin
|
47
|
+
|
48
|
+
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/lib/insert_routes.rb")
|
2
|
+
|
3
|
+
class BelongsToCityGenerator < Rails::Generator::Base
|
4
|
+
attr_accessor :models, :controller, :tables, :seed
|
5
|
+
|
6
|
+
def initialize(runtime_args, runtime_options = {})
|
7
|
+
super
|
8
|
+
usage if (!@args.empty? and (['tables', 'models', 'controller', 'seed'] - @args).size == 4)
|
9
|
+
end
|
10
|
+
|
11
|
+
def manifest
|
12
|
+
record do |m|
|
13
|
+
|
14
|
+
if @args.empty? or @args.include?('tables')
|
15
|
+
m.migration_template "migrate/create_belongs_to_city_tables.rb", "db/migrate", :migration_file_name => "create_belongs_to_city_tables"
|
16
|
+
end
|
17
|
+
if @args.empty? or @args.include?('models')
|
18
|
+
m.template "models/country.rb", "app/models/country.rb"
|
19
|
+
m.template "models/state.rb", "app/models/state.rb"
|
20
|
+
m.template "models/city.rb", "app/models/city.rb"
|
21
|
+
end
|
22
|
+
if @args.empty? or @args.include?('controller')
|
23
|
+
m.template "controllers/cities_controller.rb", "app/controllers/cities_controller.rb"
|
24
|
+
m.route_resource(:cities)
|
25
|
+
end
|
26
|
+
|
27
|
+
if options[:jq_autocomplete]
|
28
|
+
m.directory "app/views/cities"
|
29
|
+
m.file "views/index.js.erb", "app/views/cities/index.js.erb"
|
30
|
+
end
|
31
|
+
|
32
|
+
if options[:include_seeds]
|
33
|
+
m.directory "db/csv"
|
34
|
+
m.file "countries.csv", "db/csv/countries.csv"
|
35
|
+
m.file "states.csv", "db/csv/states.csv"
|
36
|
+
m.file "cities.csv", "db/csv/cities.csv"
|
37
|
+
m.file 'belongs_to_city_tasks.rake', 'lib/tasks/belongs_to_city_tasks.rake'
|
38
|
+
end
|
39
|
+
|
40
|
+
include_in_environment
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
protected
|
46
|
+
|
47
|
+
def banner
|
48
|
+
<<-EOS
|
49
|
+
"#{$0}"
|
50
|
+
EOS
|
51
|
+
end
|
52
|
+
|
53
|
+
def include_in_environment
|
54
|
+
puts "****IMPORTANT****"
|
55
|
+
puts "Please include the following lines in your config/environment.rb file"
|
56
|
+
puts " config.gem 'searchlogic'"
|
57
|
+
puts " config.gem 'belongs_to_city'"
|
58
|
+
end
|
59
|
+
|
60
|
+
def add_options!(opt)
|
61
|
+
opt.separator ''
|
62
|
+
opt.separator 'Options:'
|
63
|
+
opt.on('--include-seeds', "Include seed template files on db/csv") { |v| options[:include_seeds] = true }
|
64
|
+
opt.on('--jq-autocomplete', "Include jquery autocomplete prepared view") { |v| options[:jq_autocomplete] = true }
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
Rails::Generator::Commands::Create.class_eval do
|
2
|
+
def route_resource(*resources)
|
3
|
+
resource_list = resources.map { |r| r.to_sym.inspect }.join(', ')
|
4
|
+
sentinel = 'ActionController::Routing::Routes.draw do |map|'
|
5
|
+
|
6
|
+
logger.route "map.resource #{resource_list}"
|
7
|
+
unless options[:pretend]
|
8
|
+
gsub_file 'config/routes.rb', /(#{Regexp.escape(sentinel)})/mi do |match|
|
9
|
+
"#{match}\n map.resource #{resource_list}\n"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def route_name(name, path, route_options = {})
|
15
|
+
sentinel = 'ActionController::Routing::Routes.draw do |map|'
|
16
|
+
|
17
|
+
logger.route "map.#{name} '#{path}', :controller => '#{route_options[:controller]}', :action => '#{route_options[:action]}'"
|
18
|
+
unless options[:pretend]
|
19
|
+
gsub_file 'config/routes.rb', /(#{Regexp.escape(sentinel)})/mi do |match|
|
20
|
+
"#{match}\n map.#{name} '#{path}', :controller => '#{route_options[:controller]}', :action => '#{route_options[:action]}'"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
Rails::Generator::Commands::Destroy.class_eval do
|
27
|
+
def route_resource(*resources)
|
28
|
+
resource_list = resources.map { |r| r.to_sym.inspect }.join(', ')
|
29
|
+
look_for = "\n map.resource #{resource_list}\n"
|
30
|
+
logger.route "map.resource #{resource_list}"
|
31
|
+
unless options[:pretend]
|
32
|
+
gsub_file 'config/routes.rb', /(#{look_for})/mi, ''
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def route_name(name, path, route_options = {})
|
37
|
+
look_for = "\n map.#{name} '#{path}', :controller => '#{route_options[:controller]}', :action => '#{route_options[:action]}'"
|
38
|
+
logger.route "map.#{name} '#{path}', :controller => '#{route_options[:controller]}', :action => '#{route_options[:action]}'"
|
39
|
+
unless options[:pretend]
|
40
|
+
gsub_file 'config/routes.rb', /(#{look_for})/mi, ''
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
Rails::Generator::Commands::List.class_eval do
|
46
|
+
def route_resource(*resources)
|
47
|
+
resource_list = resources.map { |r| r.to_sym.inspect }.join(', ')
|
48
|
+
logger.route "map.resource #{resource_list}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def route_name(name, path, options = {})
|
52
|
+
logger.route "map.#{name} '#{path}', :controller => '{options[:controller]}', :action => '#{options[:action]}'"
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'fastercsv'
|
3
|
+
|
4
|
+
namespace :db do
|
5
|
+
namespace :seed do
|
6
|
+
task :cities => :environment do
|
7
|
+
|
8
|
+
puts 'Creating countries...'
|
9
|
+
FasterCSV.foreach('db/csv/countries.csv', :headers => :first_row) do |country|
|
10
|
+
Country.create(:name => country['name'])
|
11
|
+
end
|
12
|
+
puts 'done'
|
13
|
+
|
14
|
+
puts 'Creating States'
|
15
|
+
FasterCSV.foreach('db/csv/states.csv', :headers => :first_row) do |state|
|
16
|
+
State.create(:country_id => state['country_id'], :name => state['name'], :abbr => state['abbr'], :short => state['short'], :short2 => state['short2'])
|
17
|
+
end
|
18
|
+
puts 'done'
|
19
|
+
|
20
|
+
puts 'Creating Cities'
|
21
|
+
FasterCSV.foreach('db/csv/cities.csv', :headers => :first_row) do |city|
|
22
|
+
City.create(:state_id => city['state_id'], :name => city['name'], :city_name => city['city_name'])
|
23
|
+
end
|
24
|
+
puts 'Done'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class CreateBelongsToCityTables < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :countries do |t|
|
4
|
+
t.string :name
|
5
|
+
end
|
6
|
+
add_index :countries, :name
|
7
|
+
|
8
|
+
create_table :states do |t|
|
9
|
+
t.integer :country_id
|
10
|
+
t.string :name
|
11
|
+
t.string :abbr
|
12
|
+
t.string :short
|
13
|
+
t.string :short2
|
14
|
+
end
|
15
|
+
add_index :states, :country_id
|
16
|
+
add_index :states, :name
|
17
|
+
add_index :states, :abbr
|
18
|
+
add_index :states, :short
|
19
|
+
add_index :states, :short2
|
20
|
+
|
21
|
+
create_table :cities do |t|
|
22
|
+
t.integer :state_id
|
23
|
+
t.string :name
|
24
|
+
t.string :city_name
|
25
|
+
end
|
26
|
+
add_index :cities, :name
|
27
|
+
add_index :cities, :city_name
|
28
|
+
add_index :cities, :state_id
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.down
|
32
|
+
drop_table :countries
|
33
|
+
drop_table :states
|
34
|
+
drop_table :cities
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class City < ActiveRecord::Base
|
2
|
+
belongs_to :state
|
3
|
+
|
4
|
+
def self.find_by_full_name(full_name)
|
5
|
+
unless full_name.blank?
|
6
|
+
city_name, state_name = full_name.split(",")
|
7
|
+
@cities = City.name_like(city_name.strip)
|
8
|
+
@cities = @cities.state_name_or_state_abbr_like(state_name.strip) if state_name
|
9
|
+
@cities
|
10
|
+
else
|
11
|
+
[]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module BelongsToCity
|
2
|
+
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
|
9
|
+
def belongs_to_city(args = {})
|
10
|
+
city_attribute = args[:as].nil? ? :city : args[:as]
|
11
|
+
city_attribute_helper = (city_attribute.to_s + '_name').to_sym
|
12
|
+
city_collector = city_attribute.to_s.pluralize.to_sym
|
13
|
+
|
14
|
+
attr_accessor city_collector
|
15
|
+
belongs_to city_attribute, :class_name => "City"
|
16
|
+
|
17
|
+
#Getter and Setter Methods
|
18
|
+
define_method "#{city_attribute}_name" do
|
19
|
+
return read_attribute("#{city_attribute}_name") if read_attribute("#{city_attribute}_name")
|
20
|
+
return "#{send(city_attribute).name}, #{send(city_attribute).state.short2}" if read_attribute(city_attribute)
|
21
|
+
end
|
22
|
+
|
23
|
+
define_method "#{city_attribute}_name=" do |city_name|
|
24
|
+
write_attribute("#{city_attribute}_name", city_name)
|
25
|
+
write_attribute(city_collector, City.find_by_full_name(city_name) || [])
|
26
|
+
if read_attribute(city_collector).size == 1
|
27
|
+
send "#{city_attribute}=", read_attribute(city_collector).first
|
28
|
+
else
|
29
|
+
send "#{city_attribute}=", nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
#Validation Methods
|
34
|
+
if args[:required]
|
35
|
+
if args[:messages]
|
36
|
+
too_many_cities_message = args[:messages][:on_many_matches]
|
37
|
+
no_cities_message = args[:messages][:on_no_matches]
|
38
|
+
end
|
39
|
+
too_many_cities_message ||="Too many cities found in your request, please be more specific"
|
40
|
+
no_cities_message ||= "We couldn't find any city in your request"
|
41
|
+
validate do |record|
|
42
|
+
cities = record.read_attribute(city_collector)
|
43
|
+
record.errors.add(city_attribute_helper, too_many_cities_message) if cities.size > 1 rescue nil
|
44
|
+
record.errors.add(city_attribute_helper, no_cities_message) if (cities.nil? or cities.size == 0)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
class ActiveRecord::Base
|
55
|
+
include BelongsToCity
|
56
|
+
end
|
metadata
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: belongs_to_city
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 6
|
8
|
+
- 0
|
9
|
+
version: 0.6.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Adrian Cuadros
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-05-21 00:00:00 -05:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: thoughtbot-shoulda
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :development
|
31
|
+
version_requirements: *id001
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: searchlogic
|
34
|
+
prerelease: false
|
35
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
segments:
|
40
|
+
- 0
|
41
|
+
version: "0"
|
42
|
+
type: :development
|
43
|
+
version_requirements: *id002
|
44
|
+
- !ruby/object:Gem::Dependency
|
45
|
+
name: fastercsv
|
46
|
+
prerelease: false
|
47
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
segments:
|
52
|
+
- 0
|
53
|
+
version: "0"
|
54
|
+
type: :development
|
55
|
+
version_requirements: *id003
|
56
|
+
description: Creates the basic structure to enable City structure integration with any model and eases autocomplete search
|
57
|
+
email: adrian@innku.com
|
58
|
+
executables: []
|
59
|
+
|
60
|
+
extensions: []
|
61
|
+
|
62
|
+
extra_rdoc_files:
|
63
|
+
- LICENSE
|
64
|
+
- README.textile
|
65
|
+
files:
|
66
|
+
- .gitignore
|
67
|
+
- LICENSE
|
68
|
+
- README.textile
|
69
|
+
- Rakefile
|
70
|
+
- VERSION
|
71
|
+
- belongs_to_city.gemspec
|
72
|
+
- generators/belongs_to_city/USAGE
|
73
|
+
- generators/belongs_to_city/belongs_to_city_generator.rb
|
74
|
+
- generators/belongs_to_city/lib/insert_routes.rb
|
75
|
+
- generators/belongs_to_city/templates/belongs_to_city_tasks.rake
|
76
|
+
- generators/belongs_to_city/templates/cities.csv
|
77
|
+
- generators/belongs_to_city/templates/controllers/cities_controller.rb
|
78
|
+
- generators/belongs_to_city/templates/countries.csv
|
79
|
+
- generators/belongs_to_city/templates/migrate/create_belongs_to_city_tables.rb
|
80
|
+
- generators/belongs_to_city/templates/models/city.rb
|
81
|
+
- generators/belongs_to_city/templates/models/country.rb
|
82
|
+
- generators/belongs_to_city/templates/models/state.rb
|
83
|
+
- generators/belongs_to_city/templates/states.csv
|
84
|
+
- generators/belongs_to_city/templates/views/index.js.erb
|
85
|
+
- lib/belongs_to_city.rb
|
86
|
+
has_rdoc: true
|
87
|
+
homepage: http://github.com/adriancuadros/belongs_to_city
|
88
|
+
licenses: []
|
89
|
+
|
90
|
+
post_install_message:
|
91
|
+
rdoc_options:
|
92
|
+
- --charset=UTF-8
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
segments:
|
100
|
+
- 0
|
101
|
+
version: "0"
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
segments:
|
107
|
+
- 0
|
108
|
+
version: "0"
|
109
|
+
requirements: []
|
110
|
+
|
111
|
+
rubyforge_project:
|
112
|
+
rubygems_version: 1.3.6
|
113
|
+
signing_key:
|
114
|
+
specification_version: 3
|
115
|
+
summary: Eases integrating a city database structure with any model in rails
|
116
|
+
test_files: []
|
117
|
+
|