Sinatra + ActiveRecord + MySQL で簡易アプリつくってみる


寒くなるとプログラムをやりたくなるのか、ここ数日は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 TABLE topics (
  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:

 

 

Similar Posts:


Leave a Reply

Your email address will not be published. Required fields are marked *