寒くなるとプログラムをやりたくなるのか、ここ数日はRubyな日々が続いていて、今回は前回と同じ題材で勉強会関連のJSONを引っ張ってくるアプリですが、複数のウェブからとなるとやっぱりDBは必須となってくるわけで、WebとDBの連携を自分でやるのは初めてなので試行錯誤な感じが続きましたがやっと出来上がりました。
やっぱりDBを勉強する。というよりも必要なのでDBを勉強したという事象の方が自分には性に合っているようだ。
mysql を使ってみよう
ナウいものはmysql2というやつらしく、早速Gemで入れようとしたら
libmysqlclient-devというパッケージが必要でした。
$ gem install mysql2 Building native extensions. This could take a while... Successfully installed mysql2-0.3.17 1 gem installed
これで入りました。
Gemfileを更新、増えたのはactiverecordとmysql2ですね。
$ cat Gemfile source "https://rubygems.org" gem 'sinatra' gem 'thin' gem 'activerecord' gem 'mysql2'
お次はRailsでも必要だったdatabase.ymlを作成します。
$ cat database.yml development: adapter: mysql2 database: sinatra_projects host: localhost username: root encoding: utf8
データベースを作ります
データベースはとりまえずテストをしたいので、極簡単にvarcharだけの構成で作成してみようと思いました。
create table topics ( title VARCHAR(1024) NOT NULL, address VARCHAR(2048) NOT NULL, theme VARCHAR(4096) NOT NULL );
DBへの書き込みをどうするかですが、この辺も初ですがRubyもインデントとか見た目がきれいでいいね。
ActiveRecordを使うのでまず宣言して、Topicに継承してという流れです。
ActiveRecord::Base.configurations = YAML.load_file('database.yml') ActiveRecord::Base.establish_connection('development') class Topic < ActiveRecord::Base end
DBへ書き込むコードはこんな感じで、最初は記述する場所が悪かったようで動かなかったのですが、位置を変えたらうまくいきました。
url= "https://api.atnd.org/events/?format=json&keyword=ruby" data = JSON.parse(open(url).read) data["events"].each do |item| @title = item["event"]["title"] @event_url = item["event"]["event_url"] @address = item["event"]["address"] @theme = item["event"]["catch"] topic = Topic.new topic.title = @title topic.address = @address topic.theme = @theme topic.save end
erbファイルに変数としてデータが取れるようにしましたが、この辺はだいたいで書いてみたら動いた感じです。
get '/' do @topics = Topic.all erb :index end
しかし、まだ未完成で予想していましたが、このままだとアクセスする毎にDBへ追記されちゃうのでした。その辺はあとで対応するとして、まずは動作が上手くいくところまで進めました。
あれれ~、エラーが出るよ~
日本語が書けないらしく、調べてみると文字コードがlatinだったので、utf-8にして改善できました。
Mysql2::Error: Incorrect string value
mysql> alter table topics convert to character set utf8; Query OK, 0 rows affected (0.21 sec) Records: 0 Duplicates: 0 Warnings: 0
mysql> show create table topics; CREATE TABLEtopics
(title
varchar(1024) NOT NULL,address
varchar(2048) NOT NULL,theme
varchar(4096) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 | +--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec)
これでうまく入りました。骨組みはこれで完成ですな。
mysql> select * from topics; +--------------------------------------------------+----------------------------+----------------------------------------------------------------------+ | title | address | theme | +--------------------------------------------------+----------------------------+----------------------------------------------------------------------+ | 【14人登壇!】第5回 HTML5minutes! ?triton-js? 東京都中央区晴海1-8-10 | HTML5、CSS3、JavaScript、SVG、WebGLなどについて熱く語り合おう! | | ひっそり Ruby な飲み会 | 石川県金沢市片町 | kzrb meetup mini | | あらや.rb(正式名称:cvip.rb) | | |
重複を対処しよう
重複を防ぐのにざっと考えると主キーがまず必要だな。
DBにて、"Title" をunique keyにして、INSERT IGNORE INTO table_name 構文を使ってINSERT するというのが定石なようなのでこれを考えることになる。
てことで、イベントIDをキーにして取得するようにデータベースを変更します。
atndさんの場合では必要なデータはこんな感じでしょうか。
event_id title event_url catch address place started_at
create table topics ( event_id int unique NOT NULL, event_url VARCHAR(1024) NOT NULL, title VARCHAR(1024), address VARCHAR(2048) NOT NULL, theme VARCHAR(4096) NOT NULL, place VARCHAR(1024) NOT NULL, started_at DATE );
では、作ってみましょう。
mysql> create table topics ( -> event_id int unique NOT NULL, -> event_url VARCHAR(1024) NOT NULL, -> title VARCHAR(1024), -> address VARCHAR(2048) NOT NULL, -> theme VARCHAR(4096) NOT NULL, -> place VARCHAR(1024) NOT NULL, -> started_at DATE -> ); Query OK, 0 rows affected (0.12 sec) mysql> mysql> desc topics; +------------+---------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +------------+---------------+------+-----+---------+-------+ | event_id | int(11) | NO | PRI | NULL | | | event_url | varchar(1024) | NO | | NULL | | | title | varchar(1024) | YES | | NULL | | | address | varchar(2048) | NO | | NULL | | | theme | varchar(4096) | NO | | NULL | | | place | varchar(1024) | NO | | NULL | | | started_at | date | YES | | NULL | | +------------+---------------+------+-----+---------+-------+ 7 rows in set (0.00 sec)
それでは、DBの用意ができたのでコードの方も書き換えて実行すると。
重複エラーがでちゃったが、これはこれでよし。チェックしてないし。
Mysql2::Error: Duplicate entry
いろいろ考えた結果、ActiveRecordで何かあるはず!と狙いを絞った。
そして、すぐに見つかる。
class Topic < ActiveRecord::Base validates :event_url, uniqueness: true end
確認した結果OKでした!!
見た目は前と同じだけど、実はデータベースから引っ張ってきた情報が
ウェブに表示されているという大きな違いがそこにある。
あとは他の勉強会からもデータを取得して日付でソートされれば完全体となるのだ!
Rubyをやり始めた時と違ってだんだんとイメージできるようになってきたので、進むスピードが少し上がってきた。
イメージできれば何でもできるって昔の人はよく言ったものだ。
今期はわりとアニメを多めに録っているけれど、続きが気になってるだけなのもあるので、流し見ながらひたすらコードを修正しつつやっと出来ました。
日付でソートしたいな~
ウェブだとやはりJqueryあたりになるのは仕方なす。
Tablesorterを使ってソート可能にしました。
・・・出来上がりました!
config/application.rbは要らないと思うし、ごみファイルもいろいろあるけれど置いてます|д゚)
他の勉強会関連のウェブサイトからも情報を取得するようにして、見栄えももうちっと考えてから、せっかくつくったのでvincentina.netにデプロイしようと思います。
$ tree . ├── Gemfile ├── Gemfile.lock ├── README.md ├── app.rb ├── app.rb.org ├── config │ └── application.rb ├── database.yml ├── public │ ├── css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ └── bootstrap.min.css │ ├── database.yml │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ └── glyphicons-halflings-regular.woff │ └── js │ ├── bootstrap.js │ ├── bootstrap.min.js │ ├── jquery-latest.js │ ├── jquery.min.js │ ├── jquery.tablesorter.js │ ├── jquery.tablesorter.min.js │ ├── npm.js │ ├── sortable.min.js │ ├── sortable_ja.js │ └── tablesort.min.js └── views ├── index.erb └── layout.erb
今日の出来
参考サイト
Tablesorterで HTMLの表をソート(並び替え)可能にする [ホームページ作成] All About:
atnd – 勉強会サイトのAPI比較 – Qiita: sharow
rails – Mysql2::Error: Incorrect string value – そういうことだったんですね:
Sinatra+ActiveRecord+MySQLで、簡単APIサーバ構築 – Qiita: u1-fukui
Sinatra+ActiveRecord+SQLite3で,軽量なWeb-DB連携例 | tamo’s blog: