この記事は、以下のブログ、プロジェクトのまとめです。
- Rails 5 (非beta) でつくる、APIサーバ
- RailsプロジェクトをHerokuへデプロイし、無料ホスティングしてもらう
- github: dogwood008/fetch_hatena_bookmark_and_post_to_hatena_blog
Rails 5でのプロジェクト作成
Rails 5の使用
まずは準備。
$ mkdir fetch_rss_and_post_hateblog
$ cd fetch_rss_and_post_hateblog
$ echo "gem 'rails', '~>5.0'" > Gemfile
$ mkdir .bundle
$ echo '---
BUNDLE_PATH: vendor/bundle
BUNDLE_DISABLE_SHARED_GEMS: 1
BUNDLE_BIN: ./.bin' > .bundle/config
$ sudo yum install -y sqlite-devel # 必要に応じてapt-getなど
$ bundle install
プロジェクトをセットアップ。
$ rails new . --api
$ echo "development:
secret_key_base: `rake secret`
test:
secret_key_base: `rake secret`
production:
secret_key_base: <%= ENV[\"SECRET_KEY_BASE\"] %>" > config/secrets.yml
ここまでの関係ファイルを一旦プッシュ。
$ gibo osx ruby rails vim >> .gitignore
$ git init
$ git remote add origin git://github.com/user/repo.git
$ git push origin master
APIサーバの作成
RSSを取ってきて、title, URL, descriptionを返すAPIサーバを作ってみます。
$ rails g controller post
APIモードで作られているか確認してみる。
$ cd app
$ ls
channels controllers jobs mailers views
RSSフィードを取ってきて、JSONで表示してみます。
はてブのRSSフィードを RSS:Parser#parse
で取れない件は、 はてなのAPIを使う際に503エラーが出る問題と解決策を参考にしました。
def fetch
url = 'http://b.hatena.ne.jp/dogwood008/rss'
ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36'
rss = open(url, 'User-Agent' => ua)
feed = RSS::Parser.parse(rss)
rss.close
items = feed.items.map do |i|
{ link: i.link, title: i.title, desc: i.description, date: i.dc_date }
end
render json: items
end
Rails.application.routes.draw do
get '/fetch', to: 'posts#fetch'
end
いざ、実行。
$ rails s -b 0.0.0.0
http://localhost:3000/posts/fetch
[{
link: "http://brevis.exblog.jp/24515937/",
title: "トラブルには技術的原因と、マネジメント的原因がある : タイム・コンサルタントの日誌から",
desc: "【要約と私感】“マネジメント的原因” = 仕組みの原因。手っ取り早く直すには技術的要因を取り除けば良いけど、仕組みがダメならまた似たような失敗をうむ。",
date: "2016-07-10T15:33:53.000+09:00"
},
{
link: "http://qiita.com/teradonburi/items/a382a17e1e0245b7d831",
title: "AWS料金早見表(サーバレスアーキテクチャ) - Qiita",
desc: "一度自分で一通りやってみたい感ある。",
date: "2016-07-10T15:27:49.000+09:00"
}, ...]
ヒューッ!!
その他いろいろ作ります。
Herokuへのデプロイ
Getting Started with Rails 5.x on Herokuを参考に進めていきます。
準備
herokuは PostgreSQL を推奨しているので、それに合わせる。
group :production do
gem 'pg'
end
heroku toolbeltをインストール。
$ wget -O- https://toolbelt.heroku.com/install.sh | sh
$ echo 'PATH="/usr/local/heroku/bin:$PATH"' >> ~/.bash_profile
$ source ~/.bash_profile
ログインします。予めアカウントはWebから作っておく。
$ heroku login
heroku-cli: Installing CLI... 21.83MB/21.83MB
Enter your Heroku credentials.
Email: email@example.com
Password (typing will be hidden):
Logged in as email@example.com
アプリケーションを作成~デプロイ
$ heroku create
Heroku CLI submits usage information back to Heroku. If you would like to disable this, set `skip_analytics: true` in /home/kit/.heroku/config.json
Creating app... done, ⬢ XXXXX-YYYYY-12345
https://XXXXX-YYYYY-12345.herokuapp.com/ | https://git.heroku.com/whispering-YYYYY-12345.git
origin の他に、リモートリポジトリ heroku
が追加されます。
$ git remote show heroku
* remote heroku
Fetch URL: https://git.heroku.com/XXXXX-YYYYY-12345.git
Push URL: https://git.heroku.com/XXXXX-YYYYY-12345.git
HEAD branch: (unknown)
早速、 Heroku
へプッシュしてみます。
$ git push heroku master
Counting objects: 9, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 828 bytes | 0 bytes/s, done.
Total 6 (delta 4), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Ruby app detected
remote: -----> Compiling Ruby/Rails
remote: -----> Using Ruby version: ruby-2.3.0
remote: ###### WARNING:
remote: You have the `.bundle/config` file checked into your repository
remote: It contains local state like the location of the installed bundle
remote: as well as configured git local gems, and other settings that should
remote: not be shared between multiple checkouts of a single repo. Please
remote: remove the `.bundle/` folder from your repo and add it to your `.gitignore` file.
remote: https://devcenter.heroku.com/articles/bundler-configuration
remote:
remote: -----> Installing dependencies using bundler 1.11.2
remote: Running: bundle install --without development:test --path vendor/bundle --binstubs vendor/bundle/bin -j4 --deployment
remote: Fetching gem metadata from https://rubygems.org/..........
remote: Fetching version metadata from https://rubygems.org/...
remote: Fetching dependency metadata from https://rubygems.org/..
remote: Installing rake 11.2.2
remote: Installing concurrent-ruby 1.0.2
remote: Installing i18n 0.7.0
remote: Installing thread_safe 0.3.5
remote: Installing minitest 5.9.0
remote: Installing builder 3.2.2
remote: Installing erubis 2.7.0
remote: Installing mini_portile2 2.1.0
remote: Installing pkg-config 1.1.7
remote: Installing nio4r 1.2.1 with native extensions
remote: Installing rack 2.0.1
remote: Installing websocket-extensions 0.1.2
remote: Installing arel 7.0.0
remote: Installing mime-types-data 3.2016.0521
remote: Installing method_source 0.8.2
remote: Using bundler 1.11.2
remote: Installing puma 3.4.0 with native extensions
remote: Installing thor 0.19.1
remote: Installing tzinfo 1.2.2
remote: Installing nokogiri 1.6.8 with native extensions
remote: Installing websocket-driver 0.6.4 with native extensions
remote: Installing rack-test 0.6.3
remote: Installing sprockets 3.6.3
remote: Installing mime-types 3.1
remote: Installing activesupport 5.0.0
remote: Installing mail 2.6.4
remote: Installing globalid 0.3.6
remote: Installing activemodel 5.0.0
remote: Installing activejob 5.0.0
remote: Installing activerecord 5.0.0
remote: Installing rails-dom-testing 2.0.1
remote: Installing loofah 2.0.3
remote: Installing rails-html-sanitizer 1.0.3
remote: Installing actionview 5.0.0
remote: Installing actionpack 5.0.0
remote: Installing actionmailer 5.0.0
remote: Installing actioncable 5.0.0
remote: Installing railties 5.0.0
remote: Installing sprockets-rails 3.1.1
remote: Installing rails 5.0.0
remote: Installing pg 0.18.4 with native extensions
remote: Bundle complete! 9 Gemfile dependencies, 41 gems now installed.
remote: Gems in the groups development and test were not installed.
remote: Bundled gems are installed into ./vendor/bundle.
remote: Bundle completed (19.95s)
remote: Cleaning up the bundler cache.
remote:
remote: ###### WARNING:
remote: You have the `.bundle/config` file checked into your repository
remote: It contains local state like the location of the installed bundle
remote: as well as configured git local gems, and other settings that should
remote: not be shared between multiple checkouts of a single repo. Please
remote: remove the `.bundle/` folder from your repo and add it to your `.gitignore` file.
remote: https://devcenter.heroku.com/articles/bundler-configuration
remote:
remote: ###### WARNING:
remote: No Procfile detected, using the default web server.
remote: We recommend explicitly declaring how to boot your server process via a Procfile.
remote: https://devcenter.heroku.com/articles/ruby-default-web-server
remote:
remote: -----> Discovering process types
remote: Procfile declares types -> (none)
remote: Default types for buildpack -> console, rake, web, worker
remote:
remote: -----> Compressing...
remote: Done: 23.1M
remote: -----> Launching...
remote: Released v6
remote: https://XXXXX-YYYYY-12345.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/XXXXX-YYYYY-12345.git
* [new branch] master -> master
途中で、 sqlite3.h is missing
みたいなメッセージが出たり、 「詳しくは https://devcenter.heroku.com/articles/sqlite3
を見てね」的なメッセージが出たなら、 Gemfile
の group :development
の中に gem 'sqlite'
を押し込めましょう。
group :development do
# Use sqlite3 as the database for Active Record
gem 'sqlite3'
end
必要に応じて、DBのマイグレーションを行います。
$ heroku run rake db:migrate
Running rake db:migrate on ⬢ XXXXX-YYYYY-12345... up, run.2785
D, [2016-07-12T16:25:40.173919 #3] DEBUG -- : (11.2ms) CREATE TABLE "schema_migrations" ("version" character varying PRIMARY KEY)
D, [2016-07-12T16:25:40.187941 #3] DEBUG -- : (9.3ms) CREATE TABLE "ar_internal_metadata" ("key" character varying PRIMARY KEY, "value" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
D, [2016-07-12T16:25:40.190308 #3] DEBUG -- : (1.0ms) SELECT pg_try_advisory_lock(1753797496500759360);
D, [2016-07-12T16:25:40.200901 #3] DEBUG -- : ActiveRecord::SchemaMigration Load (1.1ms) SELECT "schema_migrations".* FROM "schema_migrations"
I, [2016-07-12T16:25:40.206248 #3] INFO -- : Migrating to CreatePosts (20160710102422)
D, [2016-07-12T16:25:40.208344 #3] DEBUG -- : (0.7ms) BEGIN
== 20160710102422 CreatePosts: migrating ======================================
-- create_table(:posts)
D, [2016-07-12T16:25:40.216973 #3] DEBUG -- : (7.4ms) CREATE TABLE "posts" ("id" serial primary key, "title" character varying, "url" character varying, "comment" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
-> 0.0085s
== 20160710102422 CreatePosts: migrated (0.0087s) =============================
D, [2016-07-12T16:25:40.224358 #3] DEBUG -- : SQL (1.1ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20160710102422"]]
D, [2016-07-12T16:25:40.227280 #3] DEBUG -- : (2.6ms) COMMIT
I, [2016-07-12T16:25:40.227414 #3] INFO -- : Migrating to AddDateToPost (20160710152551)
D, [2016-07-12T16:25:40.228671 #3] DEBUG -- : (0.7ms) BEGIN
== 20160710152551 AddDateToPost: migrating ====================================
-- add_column(:posts, :date, :datetime)
D, [2016-07-12T16:25:40.230074 #3] DEBUG -- : (1.0ms) ALTER TABLE "posts" ADD "date" timestamp
-> 0.0013s
== 20160710152551 AddDateToPost: migrated (0.0014s) ===========================
D, [2016-07-12T16:25:40.231584 #3] DEBUG -- : SQL (0.8ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20160710152551"]]
D, [2016-07-12T16:25:40.233287 #3] DEBUG -- : (1.5ms) COMMIT
D, [2016-07-12T16:25:40.240319 #3] DEBUG -- : ActiveRecord::InternalMetadata Load (0.9ms) SELECT "ar_internal_metadata".* FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = $1 LIMIT $2 [["key", :environment], ["LIMIT", 1]]
D, [2016-07-12T16:25:40.248994 #3] DEBUG -- : (0.7ms) BEGIN
D, [2016-07-12T16:25:40.251805 #3] DEBUG -- : SQL (1.0ms) INSERT INTO "ar_internal_metadata" ("key", "value", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "key" [["key", "environment"], ["value", "production"], ["created_at", 2016-07-12 16:25:40 +0000], ["updated_at", 2016-07-12 16:25:40 +0000]]
D, [2016-07-12T16:25:40.253633 #3] DEBUG -- : (1.5ms) COMMIT
D, [2016-07-12T16:25:40.254643 #3] DEBUG -- : (0.8ms) SELECT pg_advisory_unlock(1753797496500759360)
これでおしまい。うまくいっていれば、ログ中に出てきたhttp://~.herokuapp.comでアクセスできる。
デバッグ
プロセス状態
heroku ps
で現在の状態を見ることができる。
$ heroku ps
Free dyno hours quota remaining this month: 1000h 0m (100%)
For more information on dyno sleeping and how to upgrade, see:
https://devcenter.heroku.com/articles/dyno-sleeping
=== web (Free): bin/rails server -p $PORT -e $RAILS_ENV (1)
web.1: up 2016/07/13 01:25:02 +0900 (~ 2m ago)
ログ
ログを見るなら heroku logs
。 --tail
オプションを付けると、リアルタイムで見られる。
$ heroku logs
$ heroku logs --tail
環境変数
# 環境変数の一覧
$ heroku config
=== XXXXX-YYYYY-12345 Config Vars
DATABASE_URL: postgres://hogehogehoge:foobarbaz@ec2-NNN-NNN-NNN-NNN.compute-M.amazonaws.com:PPPP/fugapiyo
LANG: en_US.UTF-8
RACK_ENV: production
RAILS_ENV: production
RAILS_LOG_TO_STDOUT: enabled
RAILS_SERVE_STATIC_FILES: enabled
SECRET_KEY_BASE: foobarbazhogefugapiyo
# 環境変数のうち、指定したものだけを表示
$ heroku config:get LANG
en_US.UTF-8
# 環境変数をセット
$ heroku config:set SECRET_KEY_BASE=`rake secret`
Setting SECRET_KEY_BASE and restarting ⬢ XXXXX-YYYYY-12345... done, v8
SECRET_KEY_BASE: hogefugapiyofoobarbaz
コンソール
$ heroku run rails console
Running rails console on ⬢ XXXXX-YYYYY-12345... up, run.4519
Loading production environment (Rails 5.0.0)
irb(main):001:0>
サーバの再起動
$ heroku restart
Restarting dynos on ⬢ XXXXX-YYYYY-12345... done
Heroku 無料枠の範囲
1つのサーバプロセスを立ち上げると、 1 dyno
を使用するということになります。 1 dyno
を1時間使用すると、 1 dyno hour
を消費したことになります。
各アカウントに対し 550 dyno hours
を、有効なクレジットカードを heroku に登録していれば、さらに 450 dyno hours(計 1000 dyno hours)
を一月に付与されます。
31日間の可動に必要な dyno hours
は単純計算で 744 dyno hours (= 24 hours * 31 days)
ですが、 heroku run console
や heroku run rake db:migrate
などのコマンドを実行する One-off Dyno
と呼ばれる Dyno
の実行も、利用量に含まれるので注意。
以前は「18時間稼働&6時間スリープ」のような制限がありましたが、今は上記の制限に代わりました。