概要
- 府中市が公開しているオープンデータを検索する事を事例にして、railsのアプリを作成する方法を丁寧に解説します。
作れるモノ
github
環境
- ruby (rbenv) 2.6.1
- rails 6.0.0 rc 1
- mac
使っているGem
手順
以下の手順で説明します
- rails new ! (空のアプリを作ろう)
- migration ! (テーブル作ろう)
- import ! (データをインポートしよう)
- view ! (データを表示しよう)
- search ! (データを検索できるようにしよう)
- deploy ! (herokuにアップしてみんなで使えるようにしよう)
rails new ! (空のアプリを作ろう)
> bundle init
Writing new Gemfile to /Users/junara/IdeaProjects/opendata/Gemfile
> ls
Gemfile Gemfile.lock
railsをインストールするために gem "rails"
のコメントをアウトを外します。
# frozen_string_literal: true
source "https://rubygems.org"
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
gem "rails", '~> 6.0.0.rc1'
bundle install
# 省略
今いる場所にrailsを作成します。
pwd
# 今の場所がわかる
rails new .
ここでいちど起動を確認しましょう
rails s
http://localhost:3000
にアクセスします。下記の画面が出たら成功です。
migration ! (テーブル作ろう)
今回対象となるデータを見ます。 府中産農産物直売所マップ(平成30年11月現在) (CSV:11KB)
インポートするデータを府中市のHPからダウンロードして中身を見ます。
府中産農産物直売所マップ(平成30年11月現在) (CSV:11KB)
エディタによっては、へんな文字が羅列されているかもしれません。
これは、文字コードをうまく認識できていないことが問題です。
文字コードは複数種類ありますが、今だったらshift-jisとutf-8どちらかを試せば解決することが多いです。(エディタによってやり方が違うのでそちらは各自しらべてください。)
今回はshift-jisを選ぶと文字がキチンと日本語で表示されます。
№,名 前,直売所住所,電話番号,営業時間,販売期間,休業日,販売品目,コメント
# 省略
取り込むmodelを作成します。model名とカラム名を考えましょう
今回は、お店のデータなのでテーブル名は Store とします。
rails g model store ?[HEAD]
Running via Spring preloader in process 84006
invoke active_record
create db/migrate/20190310103813_create_stores.rb
create app/models/store.rb
invoke test_unit
create test/models/store_test.rb
create test/fixtures/stores.yml
次にカラム名です。カラム名は、取り込みたいデータのないようで決めます。
取り込みたいデータとは、前記のCSVをみて考えます。
もちろん、全部のデータを取り込むこともできます。ただ、無駄なデータを取り込むのはデータベースを肥大化させるだけなので、まずは必要なデータ、使用する列だけを取り込みます。
とりあえず、今回必要とするのは 名 前
と 販売品目
列とします。
これにあわせてmigrationを作成しましょう
class CreateStores < ActiveRecord::Migration[6.0]
def change
create_table :stores do |t|
t.string :name, comment: '名 前'
t.string :description, comment: '販売品目'
t.timestamps
end
end
end
migrationファイルが作られたら、migrationを実行して、tableを作成しましょう。
rails db:migrate ?[HEAD]
== 20190310103813 CreateStores: migrating =====================================
-- create_table(:stores)
-> 0.0113s
== 20190310103813 CreateStores: migrated (0.0113s) ============================
これで、必要なmodel, tableの作成が終了しました。
import ! (データをインポートしよう)
下記のgemを入れます。importするときの定番。
gem 'activerecord-import'
bundle install
# 省略
取り込むためのメソッドをStoreモデルに書きます。
require 'csv'
class Store < ApplicationRecord
def self.import_csv(file)
list = []
CSV.foreach(file, encoding: 'cp932', headers: true) do |row|
list << self.new(store_params(row))
end
import list
end
def self.store_params(row)
{
name: row['名 前'],
description: row['販売品目']
}
end
end
先ほど db/30chokubaijo_map.csv
に保存したcsvをインポートします。
rails c
irb > Store.import_csv('db/30chokubaijo_map.csv')
(0.2ms) SELECT sqlite_version(*)
(0.1ms) begin transaction
(0.1ms) SAVEPOINT active_record_1
# 省略
(0.1ms) RELEASE SAVEPOINT active_record_1
(0.8ms) commit transaction
=> #<struct ActiveRecord::Import::Result failed_instances=[], num_inserts=1, ids=[], results=[]>
保存されているか確認します。
irb > Store.first.description
Store Load (0.2ms) SELECT "stores".* FROM "stores" ORDER BY "stores"."id" ASC LIMIT ? [["LIMIT", 1]]
=> "トマト、きゅうり、おくら、いんげん、キャベツ、さつまいも、ブロッコリー、ねぎ、なす、モロヘイヤ、ピーマン、紫イモ、カリフラワー、じゃがいも、里いも、大根、ほうれん草、水菜 ほか"
irb(main):009:0> Store.count
(0.2ms) SELECT COUNT(*) FROM "stores"
=> 46
view ! (データを表示しよう)
ルートを追加します。
Rails.application.routes.draw do
root to: 'home#index'
end
上記で追加したhomeのアクションを行うコントローラーを新規で追加します。
class HomeController < ApplicationController
def index
@stores = Store.all
end
end
<h2>
府中産農産物直売所一覧
</h2>
<% @stores.each do |store| %>
<div>
<h3>
<%= store.name %>
</h3>
<div>
<%= store.description %>
</div>
</div>
<% end %>
ここで確認します。
http://localhost:3000/
search ! (データを検索できるようにしよう)
Activerecordでやるのは面倒なので、定番の検索のgem ransackを入れます。
gem 'ransack'
で、インストール
bundle install
検索するために、indexアクションを修正します。
ransackの使い方は公式をどうぞ。
class HomeController < ApplicationController
def index
@stores = Store.ransack(description_cont: params[:keyword]).result
end
end
検索フォームをviewについかします。
<h2>
府中産農産物直売所一覧
</h2>
<div>
<%= form_with url: root_path, method: :get, local: true do |f| %>
<%= f.text_field :keyword, value: params[:keyword], autocomplete: 'off' %>
<%= f.submit '検索' %>
<% end %>
</div>
<% @stores.each do |store| %>
<div>
<h3>
<%= store.name %>
</h3>
<div>
<%= store.description %>
</div>
</div>
<% end %>
ためします。
入力ボックスに 乳酸菌飲料
と入力すると下記のようになれば成功です。
deploy ! (herokuにアップして世界のみんなに使ってもらおう)
developmentとtest環境ではsqlite3, productionではpgをインストールします。
group :development, :test do
gem 'sqlite3'
end
group :production do
gem 'pg'
end
herokuへpushと同時に migrationが走るようにしましょう
release: bundle exec rake db:migrate
herokuのアプリを作ります。
heroku create fuchu-nosanbutsu
現行のmasterをherokuへpushします。
git push heroku master
うまくdeployされたかみましょう
heroku open
こういう表示なら成功です。
次にデータをインポートします。herokuでrails cをします。
heroku run rails c
既にやったようにインポートをします。
Store.import_csv('db/30chokubaijo_map.csv')
Store.count # -> 46
終わったらexit
exit
herokuのページを再度リロードすると前述と同様に、一覧が表示され、検索も可能なことが確認できます。
完成です!!!これで、世界の人に府中市の農産物をアピールできました!
さらに発展させるには?
作ったのは、とてーもシンプルなアプリです。更に発展させるともっと使いやすいアプリになります。ご自身の興味にしたがって色々やってみましょう。
下記は、拡張例です!
是非挑戦しましょう!
かんたんめ
- インポート対象を追加する:元のCSVには、住所などの列もあります。そちらもインポート対象にしましょう。
- インポートした列を表示に追加しましょう。
- 検索結果にページネーションを加えましょう
- 検索キーワード結果の文章にマッチしたキーワードをハイライトさせましょう。
- 複数のカラムを対象に検索できるようにしましょう
- bootstrapを導入して、装飾しましょう
- bulmaを導入して装飾しましょう
- 住所を押した時、google mapに遷移させましょう
- データを追加、編集できるフォームを追加しましょう
- herokuにdeployしましょう
そこそこ
- インポート時、重複列がある場合はupdateにしましょう
- 空白スペースで区切った場合はand検索になるようにしましょう
- 検索をページ遷移せずajaxで行いましょう
- 地図(google map)を表示させましょう
むずかしめ
- インクリメンタルサーチを入れましょう
- vue or reactでフロントを書きましょう
enjoy !