From 31850c6ca118b7828dbaa3ad1a87dab4287718f5 Mon Sep 17 00:00:00 2001 From: hellekin Date: Thu, 8 Oct 2020 22:10:41 +0200 Subject: Add categories, sections, and import data --- app/models/resource.rb | 1 + app/models/section.rb | 1 + ...4053_add_dewey_id_to_categories_and_sections.rb | 8 + ...08190558_create_join_table_resource_sections.rb | 8 + db/schema.rb | 11 +- db/seeds.rb | 22 ++ doc/import/README.md | 30 ++ doc/import/categories-fr.json | 395 +++++++++++++++++++++ 8 files changed, 475 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20201008184053_add_dewey_id_to_categories_and_sections.rb create mode 100644 db/migrate/20201008190558_create_join_table_resource_sections.rb create mode 100644 doc/import/categories-fr.json diff --git a/app/models/resource.rb b/app/models/resource.rb index e67d164..cd43bf9 100644 --- a/app/models/resource.rb +++ b/app/models/resource.rb @@ -3,6 +3,7 @@ class Resource < ApplicationRecord include UUIDParameter belongs_to :agent + has_and_belongs_to_many :sections # Figure out the requested property name def method_missing(name, *args, &block) diff --git a/app/models/section.rb b/app/models/section.rb index 0a1fbf2..6cfeb38 100644 --- a/app/models/section.rb +++ b/app/models/section.rb @@ -1,6 +1,7 @@ class Section < ApplicationRecord belongs_to :category has_one :taxonomy, through: :category + has_and_belongs_to_many :resources acts_as_list column: :rank, scope: :category diff --git a/db/migrate/20201008184053_add_dewey_id_to_categories_and_sections.rb b/db/migrate/20201008184053_add_dewey_id_to_categories_and_sections.rb new file mode 100644 index 0000000..d876b47 --- /dev/null +++ b/db/migrate/20201008184053_add_dewey_id_to_categories_and_sections.rb @@ -0,0 +1,8 @@ +class AddDeweyIdToCategoriesAndSections < ActiveRecord::Migration[6.0] + def change + add_column :categories, :dewey_id, :integer + add_column :sections, :dewey_id, :integer + add_index :categories, :dewey_id, unique: true + add_index :sections, :dewey_id, unique: true + end +end diff --git a/db/migrate/20201008190558_create_join_table_resource_sections.rb b/db/migrate/20201008190558_create_join_table_resource_sections.rb new file mode 100644 index 0000000..d01c27f --- /dev/null +++ b/db/migrate/20201008190558_create_join_table_resource_sections.rb @@ -0,0 +1,8 @@ +class CreateJoinTableResourceSections < ActiveRecord::Migration[6.0] + def change + create_join_table :resources, :sections do |t| + # t.index [:resource_id, :section_id] + # t.index [:section_id, :resource_id] + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 5a8bba7..16ba65c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2020_10_08_133300) do +ActiveRecord::Schema.define(version: 2020_10_08_190558) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -45,6 +45,8 @@ ActiveRecord::Schema.define(version: 2020_10_08_133300) do t.integer "sections_count", default: 0 t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false + t.integer "dewey_id" + t.index ["dewey_id"], name: "index_categories_on_dewey_id", unique: true t.index ["taxonomy_id"], name: "index_categories_on_taxonomy_id" end @@ -58,6 +60,11 @@ ActiveRecord::Schema.define(version: 2020_10_08_133300) do t.index ["uuid"], name: "index_resources_on_uuid", unique: true end + create_table "resources_sections", id: false, force: :cascade do |t| + t.bigint "resource_id", null: false + t.bigint "section_id", null: false + end + create_table "sections", force: :cascade do |t| t.string "name", limit: 64 t.string "summary", limit: 136 @@ -67,7 +74,9 @@ ActiveRecord::Schema.define(version: 2020_10_08_133300) do t.integer "rank", default: 0 t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false + t.integer "dewey_id" t.index ["category_id"], name: "index_sections_on_category_id" + t.index ["dewey_id"], name: "index_sections_on_dewey_id", unique: true end create_table "taxonomies", force: :cascade do |t| diff --git a/db/seeds.rb b/db/seeds.rb index 8a4c670..ea9fc25 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -26,3 +26,25 @@ Taxonomy.find_or_create_by( uuid: '2519915f-d19c-4281-b758-f5ddb889d7fa', agent_id: dewey.id ) + +# Create French categories and sections +if Category.count == 0 + dewey_taxo = Taxonomy.first + cats = JSON.parse(IO.read('doc/import/categories-fr.json')) + cats.each do |cat| + c = Category.create(name: cat['name'], dewey_id: cat['id'], taxonomy_id: dewey_taxo.id, color: cat['color']) + cat['sections'].each do |sec| + Section.create(name: sec['name'], category_id: c.id, dewey_id: sec['id'], color: sec['color']) + end + end + # Now that we have all we need, update resources_sections... + Resource.all.each do |res| + sec_ids = res.feature['properties']['categories'] + next if sec_ids.empty? + sec_ids.each do |id| + s = Section.find_by(dewey_id: id) + res.sections << s if s.present? + res.save + end + end +end diff --git a/doc/import/README.md b/doc/import/README.md index b65225e..f5c4096 100644 --- a/doc/import/README.md +++ b/doc/import/README.md @@ -30,3 +30,33 @@ locs['features'].each do |f| Resource.create(agent_id: agent.id, feature: f) end ``` +### Importing categories + +We have a JSON file in French for categories in `doc/import/categories-fr.json`. + +From the console: + +```ruby +if Category.count == 0 + dewey_taxo = Taxonomy.first + cats = JSON.parse(IO.read('doc/import/categories-fr.json')) + cats.each do |cat| + c = Category.create(name: cat['name'], dewey_id: cat['id'], taxonomy_id: dewey_taxo.id, color: cat['color']) + cat['sections'].each do |sec| + Section.create(name: sec['name'], category_id: c.id, dewey_id: sec['id'], color: sec['color']) + end + end + # Now that we have all we need, update resources_sections... + Resource.all.each do |res| + sec_ids = res.feature['properties']['categories'] + next if sec_ids.empty? + sec_ids.each do |id| + s = Section.find_by(dewey_id: id) + res.sections << s if s.present? + res.save + end + end +end +``` + +It's taken into account in `rails db:seed` diff --git a/doc/import/categories-fr.json b/doc/import/categories-fr.json new file mode 100644 index 0000000..ec22790 --- /dev/null +++ b/doc/import/categories-fr.json @@ -0,0 +1,395 @@ +[ + { + "id": 8, + "name": "Se loger", + "sections": [ + { + "id": 148, + "name": "Campings" + }, + { + "id": 158, + "name": "Maisons de soin" + }, + { + "id": 130, + "name": "Community land trust" + }, + { + "id": 198, + "name": "Community living (for the homeless)" + }, + { + "id": 150, + "name": "Homeless shelters (by night)" + }, + { + "id": 149, + "name": "Auberges de jeunesse" + }, + { + "id": 165, + "name": "Coopérative d'habitants" + }, + { + "id": 131, + "name": "Occupations légalisées" + }, + { + "id": 168, + "name": "Participatory housing, cohousing" + }, + { + "id": 164, + "name": "Coopératives de locataires" + }, + { + "id": 114, + "name": "Droit au logement" + } + ], + "color": "#BCBCBC" + }, + { + "id": 6, + "name": "1. S'alimenter", + "sections": [ + { + "name": "Marchés", + "id": 170 + }, + { + "name": "Ateliers cuisine", + "id": 180 + }, + { + "name": "Spots 'plantes aromatiques'", + "id": 155 + }, + { + "name": "Épiceries solidaires", + "id": 135 + }, + { + "name": "Eau potable", + "id": 115 + }, + { + "name": "Repas gratuits", + "id": 154 + }, + { + "name": "Restaurants sociaux", + "id": 118 + }, + { + "name": "Initiatives de récup' alimentaire", + "id": 28 + }, + { + "name": "GASAP (groupes d'achat)", + "id": 27 + }, + { + "name": "GASAP (producteurs)", + "id": 185 + } + ], + "color": "#FF9200" + }, + { + "id": 11, + "name": "2. Se laver, s'habiller", + "sections": [ + { + "name": "Boîtes à dons", + "id": 210 + }, + { + "name": "Vestiaires sociaux", + "id": 156 + }, + { + "name": "Donneries, marchés gratuits", + "id": 46 + }, + { + "name": "Douches publiques", + "id": 144 + }, + { + "name": "Friperies, vêtements de 2ème main", + "id": 104 + } + ], + "color": "#FFEB00" + }, + { + "id": 10, + "name": "3. Guérir, se soigner", + "sections": [ + { + "name": "Maisons médicales", + "id": 18 + }, + { + "name": "Réseaux de santé", + "id": 145 + }, + { + "name": "Services de santé pour personnes précaires", + "id": 157 + } + ], + "color": "#7CFB80" + }, + { + "id": 15, + "name": "4. Recycler, réparer", + "sections": [ + { + "name": "Magasins de seconde main", + "id": 699 + }, + { + "name": "Ateliers de travail du bois", + "id": 138 + }, + { + "name": "Récup' de cartouches d'imprimantes", + "id": 136 + }, + { + "name": "Boîtes à livres", + "id": 50 + }, + { + "name": "Aide au compostage", + "id": 132 + }, + { + "name": "Repair cafés", + "id": 42 + }, + { + "name": "Récup' de matériaux de construction", + "id": 113 + }, + { + "name": "Bulles à vêtements", + "id": 206 + }, + { + "name": "Matériaux informatiques recyclés", + "id": 47 + }, + { + "name": "Recyclage de verre", + "id": 205 + }, + { + "name": "Marchés aux puces", + "id": 120 + } + ], + "color": "#02ACCC" + }, + { + "id": 7, + "name": "5. respirer, se mettre au vert", + "sections": [ + { + "name": "Soutien aux potagistes", + "id": 128 + }, + { + "name": "Composts collectifs ou 'de quartier'", + "id": 121 + }, + { + "name": "Potagers & vergers", + "id": 116 + }, + { + "name": "Réserves naturelles", + "id": 133 + }, + { + "name": "Associations de naturalistes", + "id": 194 + }, + { + "name": "Parcs publics", + "id": 129 + }, + { + "name": "Grainothèques, bourses aux semences", + "id": 125 + }, + { + "name": "Associations apicoles", + "id": 127 + } + ], + "color": "#97C000" + }, + { + "id": 3, + "name": "6. Se rencontrer, s'entraider", + "sections": [ + { + "name": "Comités de quartiers", + "id": 102 + }, + { + "name": "Associations de soutien aux seniors", + "id": 19 + }, + { + "name": "Maisons de Jeunes", + "id": 17 + }, + { + "name": "Soutien à l'enfance et à la famille", + "id": 14 + }, + { + "name": "Maisons de quartiers", + "id": 10 + }, + { + "name": "Monnaies complémentaires", + "id": 211 + }, + { + "name": "Associations de soutien scolaire", + "id": 119 + }, + { + "name": "Associations de Femmes", + "id": 15 + }, + { + "name": "Accueil des réfugiés", + "id": 188 + }, + { + "name": "Soutien aux personnes en situation d'handicap", + "id": 16 + }, + { + "name": "Accueil des primo-arrivants", + "id": 197 + }, + { + "name": "Coopération et solidarité internationale", + "id": 209 + }, + { + "name": "Associations pour l'égalité des genres", + "id": 202 + }, + { + "name": "Centres communautaires NL", + "id": 204 + }, + { + "name": "Initiatives de récup' alimentaire", + "id": 201 + }, + { + "name": "Soutien aux personnes précaires", + "id": 193 + }, + { + "name": "Systèmes d'échange locaux (SEL)", + "id": 184 + } + ], + "color": "#C6B117" + }, + { + "id": 2, + "name": "7. Apprendre, se former", + "sections": [ + { + "name": "Association d'écologie urbaine", + "id": 90 + }, + { + "name": "Espaces de travail partagés, co-working", + "id": 87 + }, + { + "name": "Soutien à l'économie locale", + "id": 12 + }, + { + "name": "Associations d'éducation permanente", + "id": 13 + } + ], + "color": "#7E8AE0" + }, + { + "id": 13, + "name": "8. S'exprimer, communiquer", + "sections": [ + { + "name": "Bornes d'accès à Internet", + "id": 124 + }, + { + "name": "Hackerspaces", + "id": 43 + }, + { + "name": "Médias indépendants", + "id": 109 + }, + { + "name": "Écrivains publics", + "id": 177 + }, + { + "name": "Lieux de promotion du logiciel libre", + "id": 174 + } + ], + "color": "#677362" + }, + { + "id": 9, + "name": "9. Bouger, se déplacer", + "sections": [ + { + "name": "Cours de vélo", + "id": 179 + }, + { + "name": "Ateliers vélo", + "id": 71 + }, + { + "name": "Vélos partagés", + "id": 147 + }, + { + "name": "Livraisons à vélo", + "id": 140 + }, + { + "name": "Pompes à vélos", + "id": 212 + }, + { + "name": "Taxis collectifs (Collecto)", + "id": 196 + }, + { + "name": "Voitures partagées", + "id": 141 + } + ] + } +] -- cgit v1.2.3