belongs_to_city 0.6.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/.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
|
+
|