キーワードで位置情報を検索して検索結果の任意の情報をDBへ保存、そして、DBへ保存した位置情報をGoogle Mapsで表示するアプリケーションを作ってみます。

キーワードから位置情報を検索するのに、Google Places APIのRuby用のラッパーライブラリであるmarceldegraaf/google_placesをRails4アプリケーションにインストールします。

DBへ保存した位置情報をGoogle Mapsで表示させるのに、gmaps4railsをRails4アプリケーションにインストールします。

また、作成したアプリケーションはherokuにpushしますのでRailsのデータベースドライバとしてPostgreSQLを選択します。

PostgreSQLの準備

PostgreSQLインストール

CentOS6でPostgreSQLインストール

データベースユーザ作成

PostgreSQLにpostgresユーザで接続します。

1
psql --username=postgres

create userSQLを実行して、データベースユーザとしてgoogle_place_sampleをDB作成権限を付与して作成します。

1
create user google_place_sample with createdb password 'google_place_sample';

Railsプロジェクト作成

Railsプロジェクト作成

新しいRailsプロジェクトを作成します。

1
2
3
rails new google_place_sample --database=postgresql
cd google_place_sample
bin/spring stop

therubyracer

GemfileのJavascriptエンジンであるtherubyracerの設定行をアンコメントします。

Gemfile
1
2
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
gem 'therubyracer',  platforms: :ruby

therubyracerライブラリをインストールします。

1
bundle install

PostgreSQLデータベース接続設定

PostgreSQLデータベース接続情報に接続データベースユーザの情報を追記します。

config/database.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
default: &default
  adapter: postgresql
  encoding: unicode
  pool: 5

development:
  <<: *default
  database: google_place_sample_development
  user: google_place_sample
  password: google_place_sample

test:
  <<: *default
  database: google_place_sample_test
  user: google_place_sample
  password: google_place_sample

production:
  <<: *default
  database: google_place_sample_production
  username: google_place_sample
  password: <%= ENV['GOOGLE_PLACE_SAMPLE_DATABASE_PASSWORD'] %>

Bootstrap3インストール

Gemライブラリのインストール


Gemfileに追記します。

Gemfile
1
2
3
4
5
6
7
8
# Install Twitter Bootstrap3
# https://github.com/twbs/bootstrap-sass
gem 'bootstrap-sass', '~> 3.2.0'

# -webkit-border-radius みたいなブラウザベンダープレフィックスをよしなに管理してくれる
# Parse CSS and add vendor prefixes to rules by Can I Use
# https://twitter.com/autoprefixer
gem 'autoprefixer-rails'

Gemライブラリをインストールします。

1
bundle install

bootstrap-sassを使用する準備

今回はSassというプリプロセッサに対応したbootstrap3をインストールしているのですが、CSSの//= require行はSassでは文法として使用できない>ので注意が必要です。そして、Sass拡張子のファイルやその他のスタイルシートであっても、Bootstrapからmixinsや変数を利用できないので//= require>行は利用できないということです。

本家GiHubのREADMEに従い、app/assets/stylesheets/application.cssは削除します。

1
rm app/assets/stylesheets/application.css

app/assets/stylesheets/application.css.scssを新規作成します。

app/assets/stylesheets/application.css.scss
1
2
@import "bootstrap-sprockets";
@import "bootstrap";

app/assets/javascripts/application.jsにBootstrap関連のJavascriptsライブラリをrequireします。

app/assets/javascripts/application.js
1
//= require bootstrap-sprockets

app/views/layouts/application.html.erbheadタグにbootstrap関連のスタイルシートをincludeする設定とメディアクエリーを使用するためのviewport設定を追記します。

app/views/layouts/application.html.erb headタグ内の記述
1
2
  <%= stylesheet_link_tag    "bootstrap", media: "all", "data-turbolinks-track" => true %>
  <meta content="width=device-width, initial-scale=1" name="viewport">

ナビゲーションメニュー

app/views/layouts/application.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  <div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
    <div class="container">
      <div class="navbar-header">
        <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
          <span class="sr-only">Toggle navigation</span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
        </button>
        <a class="navbar-brand" href="/">Project name</a>
      </div>
      <div class="collapse navbar-collapse">
        <ul class="nav navbar-nav">
          <li class="active"><a href="/">Home</a></li>
          <li><a href="#about">About</a></li>
          <li><a href="#contact">Contact</a></li>
        </ul>
        <form class="navbar-form navbar-left">
          <input type="text" class="form-control col-lg-8" placeholder="Search">
        </form>
      </div><!--/.nav-collapse -->
    </div><!-- /.container -->
  </div><!-- /.navbar -->

Jumbotron(ジャンボトロン)

app/assets/stylesheets/theme-style.css.scssを作成し、スタイルを追加します。

app/assets/stylesheets/theme-style.css.scss
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
body {
  padding-top: 70px;
  padding-bottom: 30px;
}

.theme-dropdown .dropdown-menu {
  position: static;
  display: block;
  margin-bottom: 20px;
}

.theme-showcase > p > .btn {
  margin: 5px 0;
}

.theme-showcase .navbar .container {
  width: auto;
}

app/assets/stylesheets/application.css.scssに作成したtheme-style.css.scssを読む込むように設定します。

app/assets/stylesheets/application.css.scss
1
@import "theme-style";

次にJumbotron(ジャンボトロン)を表示するためのコードを記述します。

app/views/layouts/application.html.erb
1
2
3
4
5
6
7
8
9
10
  <div class="container theme-showcase" role="main">
    <!-- Main jumbotron -->
    <div class="jumbotron">
      <h1>Hello, world!</h1>
      <p class="text-warning">bootstrap3-sample</p>
    </div><!-- /.jumbotron -->

    <%= yield %>

  </div><!-- /.container -->

Railsのフラッシュメッセージ表示

コントローラ内でModelの保存や削除の成功/失敗などのメッセージを変数に格納された場合にはJumbotron(ジャンボトロン)の上部にします。

app/views/layouts/application.html.erb
1
2
3
4
5
6
7
8
9
  <% if (notice) %>
    <div class="alert alert-info alert-dismissible" role="alert">
      <button type="button" class="close" data-dismiss="alert">
        <span aria-hidden="true">&times;</span>
        <span class="sr-only">閉じる</span>
      </button>
      <strong><%= notice %></strong>
    </div>
  <% end %>

google_placesライブラリでキーワードから位置情報を取得する

https://github.com/marceldegraaf/google_placesをインストールすることで、東京 焼き肉とか沖縄 しまぶた屋などのキーワードで検索して位置情報などを取得することができるようになります。

Gemライブラリのインストール

Gemfileに追記します。

Gemfile
1
2
3
# A Ruby wrapper around the Google Places API
# https://github.com/marceldegraaf/google_places
gem 'google_places'

Gemライブラリをインストールします。

1
bundle install

コントローラとビューの生成

今回はscaffoldで生成しません。

rails g controllerコマンドを使用してコントローラとビューを生成します。

アクション名 役割 ビューの生成
index 検索フォームと登録済み位置情報テーブル
list Google place API検索結果の表示
show 当該レコードの位置情報を表示
create 当該位置情報をDBへ保存
destroy 当該位置情報をDBから削除
1
bundle exec rails g controller place index list show

app/controllers/place_controller.rb

app/controllers/place_controller.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class PlaceController < ApplicationController
  before_action :set_place, only: [:show, :destroy]

  def index
    @places = Place.all
  end

  def show
  end

  def list
    keyword = params[:search]
    @client = GooglePlaces::Client.new( ENV['GOOGLE_API_KEY'] )
    @places = @client.spots_by_query( keyword )
  end

  def create
    @place = Place.new(place_params)

    respond_to do |format|
      if @place.save
        format.html { redirect_to place_index_path, notice: "#{@place.name} の位置情報を保存しました" }
      else
        format.html { render :index, notice: "#{@place.name} の位置情報を保存できませんでした" }
      end
    end
  end

  def destroy
    @place.destroy

    respond_to do |format|
      format.html { redirect_to place_index_path, notice: "#{@place.name} の位置情報を削除しました" }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_place
      @place = Place.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def place_params
      params.require(:place).permit(:name, :latitude, :longitude, :address)
    end

end

app/views/place/index.html.erb


app/views/place/index.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<h1>位置情報を検索してみよう</h1>

<div class="col-md-6">
  <%= form_tag place_list_path, :role =>"form", :method => :get do %>
    <div class="form-group">
      <%= text_field_tag :search, params[:search], { :class => "form-control", :required => true, } %>
      <%= button_tag( {:type => "submit", :name => nil, :class => "btn btn-default" } ) do %>
        <span class="glyphicon glyphicon-search">キーワード検索</span>
      <% end %>
    </div>
  <% end %>
</div>

<div class="col-md-12">
  <table class="table table-striped">
    <thead>
      <tr>
        <th>Name</th>
        <th>Latitude</th>
        <th>Longitude</th>
        <th>Address</th>
        <th colspan="2"></th>
      </tr>
    </thead>

    <tbody>
      <% @places.each do |place| %>
        <tr>
          <td><%= place.name %></td>
          <td><%= place.latitude %></td>
          <td><%= place.longitude %></td>
          <td><%= place.address %></td>
          <td><%= link_to ( place ), :title => "show" do %>
            <span class="glyphicon glyphicon-stats"></span>
          <% end %></td>
          <td><%= link_to( place, method: :delete, data: { confirm: "#{place.name} の位置情報を削除します" }, :title => "delete" ) do %>
            <span class="glyphicon glyphicon-trash"></span>
          <% end %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>

app/views/place/list.html.erb


app/views/place/list.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<h1>希望の場所は見つかったかな?</h1>

<div class="col-md-12">
  <table class="table table-striped">
    <thead>
      <tr>
        <th>Name</th>
        <th>Latitude</th>
        <th>Longitude</th>
        <th>Address</th>
        <th></th>
      </tr>
    </thead>

    <tbody>
      <% @places.each do |place| %>
        <tr>
          <td><%= place.name %></td>
          <td><%= place.lat %></td>
          <td><%= place.lng %></td>
          <td><%= place.formatted_address %></td>
          <td><%= link_to( '登録', place_index_path( :place => { :name      => place.name,
                                                                 :latitude  => place.lat,
                                                                 :longitude => place.lng,
                                                                 :address   => place.formatted_address, } ),:method => 'post' ) %>
          </td>
        </tr>
      <% end %>
    </tbody>
  </table>

  <button type="button" class="btn pull-right btn-lg btn-default">
    <%= link_to 'Back', place_index_path %>
  </button>

</div>

app/views/place/show.html.erb


app/views/place/show.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<div class="col-md-12">
  <table class="table table-striped">
    <thead>
      <tr>
        <th>Name</th>
        <th>Latitude</th>
        <th>Longitude</th>
        <th>Address</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td><%= @place.name %></td>
        <td><%= @place.latitude %></td>
        <td><%= @place.longitude %></td>
        <td><%= @place.address %></td>
      </tr>
    </tbody>
  </table>

  <button type="button" class="btn pull-right btn-lg btn-default">
    <%= link_to 'Back', place_index_path %>
  </button>

</div>

モデルの生成とDBマイグレーション

位置情報を保存するためのplaceモデルを生成します。

1
bundle exec rails g model place name:string address:string latitude:float longitude:float

DBを作成、マイグレーションを実行します。

1
2
bundle exec rake db:create
bundle exec rake db:migrate

ルーティング設定

config/routes.rb
1
2
3
4
5
6
7
8
9
10
Rails.application.routes.draw do
  root 'place#index'

  namespace :place do
    # get 'place/list' request
    get 'list'
  end

  resources :place, :only => [ :index, :show, :create, :destroy ]
end

ここまでのサンプルアプリケーション

google_placeライブラリを使った位置情報検索サンプルアプリケーション


gmaps4railsライブラリでDBに保存した位置情報からマップを作成する

ここまでの作業でキーワード検索でリストアップされた施設の位置情報をDBへ保存することが出来ました。

ここで保存している位置情報とは施設名住所経度緯度です。

経度緯度の情報があればGoogle Maps上にマークを表示させることが出来ます。

apneadiving/Google-Maps-for-Rails (gmaps4rails)ライブラリを利用することで簡単にDBに保存された経度緯度を使用してGoogle Mapsを利用できます。

Gemライブラリのインストール

Gemfile
1
2
3
4
# Enables easy Google map + overlays creation in Ruby apps 
# https://github.com/apneadiving/Google-Maps-for-Rails
# http://apneadiving.github.io/
gem 'gmaps4rails'

Gemライブラリをインストールします。

1
bundle install

gmaps4railsライブラリの使用準備

app/views/layouts/application.html.erbheadタグにGoogle Maps関連のライブラリを読み込む設定を追記します。

app/views/layouts/application.html.erb headタグ内の記述
1
2
  <script src="//maps.google.com/maps/api/js?v=3.13&amp;sensor=false&amp;libraries=geometry" type="text/javascript"></script>
  <script src='//google-maps-utility-library-v3.googlecode.com/svn/tags/markerclustererplus/2.0.14/src/markerclusterer_packed.js' type='text/javascript'></script>

app/assets/javascripts/application.jsにGoogle Maps関連のJavascriptsライブラリをrequireします。

app/assets/javascripts/application.js
1
2
//= require underscore
//= require gmaps/google

underscore/underscore.jsapp/assets/javascripts/underscore.jsとして作成します。

Google Mapsをレスポンシブで表示するスタイルシート

app/assets/stylesheets/gmap4rails.css.scss

app/assets/stylesheets/gmap4rails.css.scss
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.map_container {
    position: relative;
    width: 100%;
    margin-bottom: 20px;
    padding-bottom: 56.25%; /* Ratio 16:9 ( 100%/16*9 = 56.25% ) */
}

.map_container .map_canvas {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    margin: 0;
    padding: 0;
}

app/assets/stylesheets/gmap4rails.css.scssをimportします。

app/assets/stylesheets/application.css.scss
1
@import "gmap4rails";

showアクションでMapを表示する

app/controllers/place_controller.rb

app/controllers/place_controller.rb のshowアクション
1
2
3
4
5
6
7
  def show
    @hash = Gmaps4rails.build_markers(@place) do |place,marker|
      marker.lat place.latitude
      marker.lng place.longitude
      marker.json({title: place.name})
    end
  end

app/views/place/show.html.erb

先述したapp/views/place/show.html.erb</table>タグと<button type="button" class="btn pull-right btn-lg btn-default">タグの間に以下コードを追記します。

app/views/place/show.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  <div class="map_container">
    <div id="map" class="map_canvas"></div>
  </div>


  <script type="text/javascript">
    handler = Gmaps.build('Google');
    handler.buildMap({ provider: {}, internal: {id: 'map'}}, function(){
      markers = handler.addMarkers(<%=raw @hash.to_json %>);
      handler.bounds.extendWith(markers);
      handler.fitMapToBounds();
      handler.getMap().setZoom(12);
      handler.map.centerOn(marker);
    });
  </script>


無事、Google Mapsが表示されました!

ここまでのサンプルアプリケーション

google_placeとgmaps4railsライブラリを使った位置情報検索サンプルアプリケーション


Rails4でBootstrap3を使う(ついでにherokuへpush)で書いたエントリーからPostgreSQLインストール手順を抜き出しただけのエントリーです。

PostgreSQLの準備

PostgreSQLインストール

PostgreSQLの公式yumレポジトリからインストールします。

1
2
yum install -y http://yum.postgresql.org/9.3/redhat/rhel-6-x86_64/pgdg-redhat93-9.3-1.noarch.rpm
yum install -y postgresql93-server postgresql93-contrib postgresql93-devel

PostgreSQLインストール直後のデータベースディレクトリである/var/lib/pgsql/9.3/dataを削除してデータベースを初期化(initdb)し、postgresql-9.3サービスを起動します。ついでに、自動起動も設定します。

1
2
3
4
rm -rf /var/lib/pgsql/9.3/data
service postgresql-9.3 initdb
service postgresql-9.3 start
chkconfig postgresql-9.3 on

PostgreSQLの認証方式をPeerからTrustへ変更

https://www.postgresql.jp/document/9.3/html/auth-methods.html

PostgreSQLではデフォルトの認証方式としてPeer認証が設定されています。Peer認証とは、カーネルからクライアント上のシステムユーザ名を取得し、PostgreSQLデータベースユーザと同一である場合のみ接続が許可される仕組みです。PostgreSQLでは、デフォルトではpostgresデータベースユーザしか存在しないため、UnixユーザもPostgreSQLをパッケージインストールすると作成されているpostgresである必要があります(su - postgresしないとダメということ)。

Peer認証だとUnixのスーパーユーザであるrootであってもpostgresデータベースユーザへの接続は許可されません。

1
2
3
4
5
# id
uid=0(root) gid=0(root) 所属グループ=0(root)

# psql --username=postgres
psql: FATAL:  ユーザ "postgres" で対向(peer)認証に失敗しました

今回は、サーバに接続できる全Unixユーザから全データベースユーザへの接続が許可されるTrust認証に変更します

Peer認証からTrust認証への変更は/var/lib/pgsql/9.3/data/pg_hba.confを修正します。

/var/lib/pgsql/9.3/data/pg_hba.conf
1
2
#local   all             all                                     peer
local   all             all                                     trust

設定ファイルを修正したのでpostgresql-9.3サービスを再起動します。

1
service postgresql-9.3 restart

Railsアプリケーション用のデータベースユーザを作成

PostgreSQL 9.3ではCREATE USERはCREATE ROLEの別名になりました。 唯一の違いは、CREATE USERという名前でコマンドが呼び出されると、デフォルトでLOGINになり、CREATE ROLEという名前でコマンドが呼び出されると、デフォルトでNOLOGINとなる点です。

https://www.postgresql.jp/document/9.3/html/sql-createuser.html


PostgreSQLのスーパーユーザであるpostgresデータベースユーザで接続します。

1
psql --username=postgres

今回作成するRailsアプリケーションのプロジェクト名と同一のbootstrap3_sampleというデータベースユーザを作成し、データベース作成権限とログイン権限を持つように設定します。

1
create user bootstrap3_sample with createdb password 'bootstrap3_sample';

上記SQLは以下コマンドと同じ効果があります

1
createuser --username=postgres --createdb bootstrap3_sample -P

createuserコマンドはpostgresql93(末尾の数字はバージョン番号なので適宜目置換を!)RPMパッケージに付属しているPostgreSQLのデータベースユーザ(正確にはロール)を作成するためのコマンドです。SQLでのユーザ作成とは異なり、コマンドでパスワード文字列を指定することは出来ず、-Pオプションによってパスワード文字列を指定するプロンプトが表示されます。

データベースユーザのパスワードがシステムカタログ上に保存される際に暗号化するかどうかはENCRYPTED/UNENCRYPTEDで明示するか、そうでない場合は、/var/lib/pgsql/9.3/data/postgresql.confpassword_encryption設定パラメータに依ります。password_encryption設定パラメータがonの場合に暗号化が有効(default: on)です。

先述した通り、create userSQLはログイン権限オプション(login)を明示しなくても有効となりますし、createuserコマンドでもログイン権限オプション(–login)がデフォルトで有効なので、ここでは指定していません。この辺りのSQLやコマンドの挙動はPostgreSQLバージョンにも依ると思うので自信の無い場合はログイン権限オプションを明示した方がいいかもしれません。

サンプルアプリケーション



今まではRailsアプリケーションのデザインを独学でCSS書いたりjQueryプラグイン入れたりしてたのですが、今更ながらboootstrapを利用しようと思い始めました。

Ruby on RailsでBootstrap3をインストールする手順を纏めておきます。

今回はRailsアプリケーションのプロジェクト名としてbootstrap3_sampleという文字を使用することにします。

また、ここで使用しているRailsバージョンはRails 4.1.6です。

1
2
3
$ cd /path/to/rails_app
$ bundle exec rails -v
Rails 4.1.6

作成したアプリケーションはherokuにpushしますのでRailsのデータベースドライバとしてPostgreSQLを選択します。それに併せてPostgreSQLのインストールや設定についても自分への備忘録として残しておきます。

Bootstrapを使用するまで

PostgreSQLの準備

PostgreSQLインストール

PostgreSQLの公式yumレポジトリからインストールします。

1
2
yum install -y http://yum.postgresql.org/9.3/redhat/rhel-6-x86_64/pgdg-redhat93-9.3-1.noarch.rpm
yum install -y postgresql93-server postgresql93-contrib postgresql93-devel

PostgreSQLインストール直後のデータベースディレクトリである/var/lib/pgsql/9.3/dataを削除してデータベースを初期化(initdb)し、postgresql-9.3サービスを起動します。ついでに、自動起動も設定します。

1
2
3
4
rm -rf /var/lib/pgsql/9.3/data
service postgresql-9.3 initdb
service postgresql-9.3 start
chkconfig postgresql-9.3 on

PostgreSQLの認証方式をPeerからTrustへ変更

https://www.postgresql.jp/document/9.3/html/auth-methods.html

PostgreSQLではデフォルトの認証方式としてPeer認証が設定されています。Peer認証とは、カーネルからクライアント上のシステムユーザ名を取得し、PostgreSQLデータベースユーザと同一である場合のみ接続が許可される仕組みです。PostgreSQLでは、デフォルトではpostgresデータベースユーザしか存在しないため、UnixユーザもPostgreSQLをパッケージインストールすると作成されているpostgresである必要があります(su - postgresしないとダメということ)。

Peer認証だとUnixのスーパーユーザであるrootであってもpostgresデータベースユーザへの接続は許可されません。

1
2
3
4
5
# id
uid=0(root) gid=0(root) 所属グループ=0(root)

# psql --username=postgres
psql: FATAL:  ユーザ "postgres" で対向(peer)認証に失敗しました

今回は、サーバに接続できる全Unixユーザから全データベースユーザへの接続が許可されるTrust認証に変更します

Peer認証からTrust認証への変更は/var/lib/pgsql/9.3/data/pg_hba.confを修正します。

/var/lib/pgsql/9.3/data/pg_hba.conf
1
2
#local   all             all                                     peer
local   all             all                                     trust

設定ファイルを修正したのでpostgresql-9.3サービスを再起動します。

1
service postgresql-9.3 restart

Railsアプリケーション用のデータベースユーザを作成

PostgreSQL 9.3ではCREATE USERはCREATE ROLEの別名になりました。 唯一の違いは、CREATE USERという名前でコマンドが呼び出されると、デフォルトでLOGINになり、CREATE ROLEという名前でコマンドが呼び出されると、デフォルトでNOLOGINとなる点です。

https://www.postgresql.jp/document/9.3/html/sql-createuser.html


PostgreSQLのスーパーユーザであるpostgresデータベースユーザで接続します。

1
psql --username=postgres

今回作成するRailsアプリケーションのプロジェクト名と同一のbootstrap3_sampleというデータベースユーザを作成し、データベース作成権限とログイン権限を持つように設定します。

1
create user bootstrap3_sample with createdb password 'bootstrap3_sample';

上記SQLは以下コマンドと同じ効果があります

1
createuser --username=postgres --createdb bootstrap3_sample -P

createuserコマンドはpostgresql93(末尾の数字はバージョン番号なので適宜目置換を!)RPMパッケージに付属しているPostgreSQLのデータベースユーザ(正確にはロール)を作成するためのコマンドです。SQLでのユーザ作成とは異なり、コマンドでパスワード文字列を指定することは出来ず、-Pオプションによってパスワード文字列を指定するプロンプトが表示されます。

データベースユーザのパスワードがシステムカタログ上に保存される際に暗号化するかどうかはENCRYPTED/UNENCRYPTEDで明示するか、そうでない場合は、/var/lib/pgsql/9.3/data/postgresql.confpassword_encryption設定パラメータに依ります。password_encryption設定パラメータがonの場合に暗号化が有効(default: on)です。

先述した通り、create userSQLはログイン権限オプション(login)を明示しなくても有効となりますし、createuserコマンドでもログイン権限オプション(–login)がデフォルトで有効なので、ここでは指定していません。この辺りのSQLやコマンドの挙動はPostgreSQLバージョンにも依ると思うので自信の無い場合はログイン権限オプションを明示した方がいいかもしれません。

Railsプロジェクトの作成

新しいRailsプロジェクトを作成します。

1
2
3
rails new bootstrap3_sample --database=postgresql
cd bootstrap3_sample
bundle exec spring stop

データベース接続情報を設定

config/database.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
default: &default
  adapter: postgresql
  encoding: unicode
  pool: 5

development:
  <<: *default
  database: bootstrap3_sample_development
  user: bootstrap3_sample
  password: bootstrap3_sample

test:
  <<: *default
  database: bootstrap3_sample_test
  user: bootstrap3_sample
  password: bootstrap3_sample

production:
  <<: *default
  database: bootstrap3_sample_production
  username: bootstrap3_sample
  password: <%= ENV['BOOTSTRAP3_SAMPLE_DATABASE_PASSWORD'] %>

Gemライブラリのインストール

Rails4でBootstrap3をインストールする簡単な方法はGemライブラリを使用することです。

今回はTwitter社公式のbootstrap-sassを使用します。

比較はしていませんが、anjlab-bootstrap-railsなどもあり、anjlab/anjlab-widgetsが使えることなどが特徴のようです。こちらのGemはbootstrap-sassとの併用は推奨されていないようです。


Gemfileに追記します。therubyracerはアンコメントすれば有効になります。

Gemfile
1
2
3
4
5
6
7
8
9
10
11
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
gem 'therubyracer',  platforms: :ruby

# Install Twitter Bootstrap3
# https://github.com/twbs/bootstrap-sass
gem 'bootstrap-sass', '~> 3.2.0'

# -webkit-border-radius みたいなブラウザベンダープレフィックスをよしなに管理してくれる
# Parse CSS and add vendor prefixes to rules by Can I Use 
# https://twitter.com/autoprefixer
gem 'autoprefixer-rails'

Railsプロジェクト作成時のGemfileと比較するとこのようになります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
--- a/Gemfile
+++ b/Gemfile
@@ -12,7 +12,7 @@ gem 'uglifier', '>= 1.3.0'
 # Use CoffeeScript for .js.coffee assets and views
 gem 'coffee-rails', '~> 4.0.0'
 # See https://github.com/sstephenson/execjs#readme for more supported runtimes
-# gem 'therubyracer',  platforms: :ruby
+gem 'therubyracer',  platforms: :ruby

 # Use jquery as the JavaScript library
 gem 'jquery-rails'
@@ -38,3 +38,11 @@ gem 'spring',        group: :development
 # Use debugger
 # gem 'debugger', group: [:development, :test]

+# Install Twitter Bootstrap3
+# https://github.com/twbs/bootstrap-sass
+gem 'bootstrap-sass', '~> 3.2.0'
+
+# -webkit-border-radius みたいなブラウザベンダープレフィックスをよしなに管理してくれる
+# Parse CSS and add vendor prefixes to rules by Can I Use
+# https://twitter.com/autoprefixer
+gem 'autoprefixer-rails'

Gemライブラリをインストールします。

1
bundle install

bootstrap-sassを使用する準備

今回はSassというプリプロセッサに対応したbootstrap3をインストールしているのですが、CSSの//= require行はSassでは文法として使用できないので注意が必要です。そして、Sass拡張子のファイルやその他のスタイルシートであっても、Bootstrapからmixinsや変数を利用できないので//= require行は利用できないということです。

本家GiHubのREADMEに従い、app/assets/stylesheets/application.cssは削除します。

1
rm app/assets/stylesheets/application.css

app/assets/stylesheets/application.css.scssを新規作成します。

app/assets/stylesheets/application.css.scss
1
2
@import "bootstrap-sprockets";
@import "bootstrap";

app/assets/javascripts/application.jsにBootstrap関連のJavascriptsライブラリをrequireします。

app/assets/javascripts/application.js
1
//= require bootstrap-sprockets

app/views/layouts/application.html.erbheadタグにbootstrap関連のスタイルシートをincludeする設定とメディアクエリーを使用するためのviewport設定を追記します。

app/views/layouts/application.html.erb headタグ内の記述
1
2
  <%= stylesheet_link_tag    "bootstrap", media: "all", "data-turbolinks-track" => true %>
  <meta content="width=device-width, initial-scale=1" name="viewport">

scaffoldで骨組みを生成

scaffoldを実行します。

1
2
3
bundle exec rails g scaffold Entry name:string description:string
bundle exec rake db:create
bundle exec rake db:migrate

root_pathの設定

scaffoldで生成されたentriesリソースのindexをroot_pathに設定します。

config/routes.rb
1
  root 'entries#index'


ここでブレイク

この段階でrails serverコマンドを実行してWEBrickを起動すると以下のような画面が表示されます。

ここからBootstrapを使っていきます

ナビゲーションメニュー

bodyタグの上部にナビゲーションメニューを設置してみます。

application.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  <div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
    <div class="container">
      <div class="navbar-header">
        <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
          <span class="sr-only">Toggle navigation</span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
        </button>
        <a class="navbar-brand" href="/">Project name</a>
      </div>
      <div class="collapse navbar-collapse">
        <ul class="nav navbar-nav">
          <li class="active"><a href="/">Home</a></li>
          <li><a href="#about">About</a></li>
          <li><a href="#contact">Contact</a></li>
        </ul>
        <form class="navbar-form navbar-left">
          <input type="text" class="form-control col-lg-8" placeholder="Search">
        </form>
      </div><!--/.nav-collapse -->
    </div><!-- /.container -->
  </div><!-- /.navbar -->

Jumbotron(ジャンボトロン)

Jumbotron(ジャンボトロン)と呼ばれるページトップなどに表示する見出しユニットをbodyタグの上部、ナビゲーションメニューの下あたりに設置してみます。

まず、app/assets/stylesheets/theme-style.css.scssを作成し、スタイルを追加します。

app/assets/stylesheets/theme-style.css.scss
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
body {
  padding-top: 70px;
  padding-bottom: 30px;
}

.theme-dropdown .dropdown-menu {
  position: static;
  display: block;
  margin-bottom: 20px;
}

.theme-showcase > p > .btn {
  margin: 5px 0;
}

.theme-showcase .navbar .container {
  width: auto;
}

app/assets/stylesheets/application.css.scssに作成したtheme-style.css.scssを読む込むように設定します。

app/assets/stylesheets/application.css.scss
1
@import "theme-style";

次にJumbotron(ジャンボトロン)を表示するためのコードを記述します。

app/views/layouts/application.html.erb
1
2
3
4
5
6
7
8
9
10
  <div class="container theme-showcase" role="main">
    <!-- Main jumbotron -->
    <div class="jumbotron">
      <h1>Hello, world!</h1>
      <p class="text-warning">bootstrap3-sample</p>
    </div><!-- /.jumbotron -->

    <%= yield %>

  </div><!-- /.container -->

Railsのフラッシュメッセージ表示

後述するapp/views/entries/show.html.erb<%= notice %>というフラッシュメッセージを表示するコードがscaffoldによって自動生成されているのですが、Bootstrap3のAlertsコンポーネントを使って見栄えを良くすると同時に、先述したJumbotron(ジャンボトロン)の上部に表示するためにapp/views/layouts/application.html.erbに移動しlます。

app/views/layouts/application.html.erb
1
2
3
4
5
6
7
8
9
  <% if (notice) %>
    <div class="alert alert-info alert-dismissible" role="alert">
      <button type="button" class="close" data-dismiss="alert">
        <span aria-hidden="true">&times;</span>
        <span class="sr-only">閉じる</span>
      </button>
      <strong><%= notice %></strong>
    </div>
  <% end %>

entriesリソースのビューファイルを修正

scaffoldで生成したビューファイルに色々とBootstrap3のスタイルを適用していきます。

app/views/entries/index.html.erb

app/views/entries/index.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<h1>Listing entries</h1>
<button type="button" class="btn btn-lg btn-default">
  <%= link_to 'New Entry', new_entry_path %>
</button>
<br>

<div class="col-md-6">
  <table class="table table-striped">
    <thead>
      <tr>
        <th>Name</th>
        <th>Descriptiion</th>
        <th colspan="3"></th>
      </tr>
    </thead>
    <tbody>
      <% @entries.each do |entry| %>
        <tr>
          <td><%= entry.name %></td>
          <td><%= entry.description %></td>
          <td><%= link_to 'Show', entry %></td>
          <td><%= link_to 'Edit', edit_entry_path(entry) %></td>
          <td><%= link_to 'Destroy', entry, method: :delete, data: { confirm: 'Are you sure?' } %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>

app/views/entries/show.html.erb

app/views/entries/show.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<div class="col-md-6">
  <table class="table table-striped">
    <thead>
      <tr>
        <th>Name</th>
        <th>Descriptiion</th>
        <th></th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td><%= @entry.name %></td>
        <td><%= @entry.description %></td>
        <td><%= link_to 'Edit', edit_entry_path(@entry) %></td>
      </tr>
    </tbody>
  </table>

  <button type="button" class="btn pull-right btn-lg btn-default">
    <%= link_to 'Back', entries_path %>
  </button>

</div>

app/views/entries/new.html.erb

app/views/entries/new.html.erb
1
2
3
4
5
6
7
8
9
10
<h1>New entry</h1>

<div class="col-md-6">
  <%= render 'form' %>

  <button type="button" class="btn pull-right btn-lg btn-default">
    <%= link_to 'Back', entries_path %>
  </button>

</div>

app/views/entries/edit.html.erb

app/views/entries/edit.html.erb
1
2
3
4
5
6
7
8
9
10
<h1>Editing entry</h1>

<div class="col-md-6">
  <%= render 'form' %>

  <button type="button" class="btn pull-right btn-lg btn-default">
    <%= link_to 'Back', entries_path %>
  </button>

</div>

app/views/entries/_form.html.erb

app/views/entries/_form.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<%= form_for( (@entry), {:role => "form"} ) do |f| %>
  <% if @entry.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@entry.errors.count, "error") %> prohibited this entry from being saved:</h2>

      <ul>
      <% @entry.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <table class="table table-striped">
    <thead>
      <tr>
        <th><%= f.label :name %></th>
        <th><%= f.label :description %></th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td><%= f.text_field :name %></td>
        <td><%= f.text_field :description %></td>
      </tr>
    </tbody>
  </table>

  <%= f.submit :class => "btn btn-default" %>

<% end %>

herokuにpushしてみる

https://devcenter.heroku.com/articles/getting-started-with-rails4

Herokuを使う準備

production環境でのアセットコンパイルを有効にする

config/environments/production.rbを修正してproduction環境でのassetsを有効にします。

以下の設定パラメータを設定します。

config/environments/production.rb
1
2
3
4
config.cache_classes = true
config.serve_static_assets = true
config.assets.compile = true
config.assets.digest = true

修正後のconfig/environments/production.rbのdiff情報です。

config/environments/production.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -20,14 +20,14 @@ Rails.application.configure do
   # config.action_dispatch.rack_cache = true

   # Disable Rails's static asset server (Apache or nginx will already do this).
-  config.serve_static_assets = false
+  config.serve_static_assets = true

   # Compress JavaScripts and CSS.
   config.assets.js_compressor = :uglifier
   # config.assets.css_compressor = :sass

   # Do not fallback to assets pipeline if a precompiled asset is missed.
-  config.assets.compile = false
+  config.assets.compile = true

   # Generate digests for assets URLs.
   config.assets.digest = true

gitレポジトリを作成

herokuに対するアプリケーションのデプロイ方法はgit pushを行うことなので、ローカル環境でgitレポジトリを作成します。

1
2
3
4
cd /path/to/app
git init .
git add ./
git commit -m "initial commit"

herokuにアカウントを登録

こちらからherokuにアカウントを登録する

heroku toolbelt インストール

heroku toolbeltとは、heroku appsの作成や管理を行うためのHerokuクライアントで、実体はherokuコマンドファイルです。

herokuコマンドをインストールする方法は、OSプラットフォームにより3パターンあります。

  1. Mac OSX、またはWindowsではパッケージが提供されていますのでパッケージをダウンロードしてインストールします。
  2. Debian/Ubuntuにもdeb形式のパッケージが公開されていますが、こちらは直接ダウンロードするのではなくインストールスクリプトを利用します。
  3. Debian/Ubuntu以外のUnix/Linuxではxzファイルフォーマットで圧縮されたtarボールで配布されています。こちらもインストールスクリプトを利用します。


今回はCentOS6なので3番目のインストールスクリプトを利用します。https://toolbelt.heroku.com/standaloneの内容に沿ってインストールします。

注意点としては、インストールスクリプトの実行はsudo権限を持つユーザである必要があります(中でsudoを実行しているため)。

1
wget -qO- https://toolbelt.heroku.com/install.sh | sh

これで/usr/local/heroku/bin以下にherokuコマンドがインストールされるので、$PATH環境変数に/usr/local/heroku/binへのパスを設定しておきます。

1
echo 'export PATH=${PATH}:/usr/local/heroku/bin' >> ~/.bashrc

heroku toolbelt を使ってherokuへログイン

herokuコマンドラインツールを使ってログインします。先ほど作成したherokuアカウントのメールアドレスとパスワードを入力し、Authentication successful.と表示されればログイン成功です。また、該当Unixユーザでのログインが初めての場合は公開鍵認証に関する設定を行う場合があります。

1
heroku login

heroku appsを作成

今回はbuf-material-bootstrap3-sampleという名前のアプリケーションをheroku上に作成します。

1
heroku apps:create buf-material-bootstrap3-sample

コマンドの結果が以下のように表示されます。

URLがhttp://buf-material-bootstrap3-sample.herokuapp.com/で、heroku上に作成されるgitレポジトリのURLがgit@heroku.com:buf-material-bootstrap3-sample.git となりました。

heroku apps:create buf-material-bootstrap3-sample コマンド結果
1
2
3
Creating buf-material-bootstrap3-sample... done, stack is cedar
http://buf-material-bootstrap3-sample.herokuapp.com/ | git@heroku.com:buf-material-bootstrap3-sample.git
Git remote heroku added

heroku appsにアプリケーションをデプロイ & DBマイグレーション

herokuへのアプリケーションデプロイはなんとgit push heroku master1発なのです!

DBマイグレーションをお忘れなく。

1
2
git push heroku master
heroku run rake db:migrate

これで http://buf-material-bootstrap3-sample.herokuapp.com/ にアクセスすると先ほどローカル環境で見ていたアプリケーション画面が表示されました。

サンプルアプリケーション



Google AdSenseとは

広告収入を稼ぐためのアフィリエイトサービスと言えばいいのでしょうか。

詳細は、Google AdSenseについてwikipediaから転記します。

### http://ja.wikipedia.org/wiki/Google_AdSense から転記

Google AdSense(グーグルアドセンス)はGoogleの提供している検索連動型およびコンテンツ連動型広告の広告配信サービスの総称である。

AdSenseは、Googleが広告ネットワークに対して提供する配信サービスの総称であり、その形態は多岐にわたる。
コンテンツ向けAdSenseは所有するWebサイト(ブログでも可)にGoogle AdSenseの広告コードを貼り付けると広告が表示され、その広告がクリックされると報酬が得られる仕組みである。Google AdSenseのシステムが自動的にサイトの内容を解析し、そのサイトにあったコンテンツ連動型広告を配信するシステムである[1]。例えば、ゴルフ関連のサイトなら、自動的にゴルフの広告が表示されるよう設計されている(サイトの内容によっては、それと関連する適切な広告がなく、まったく分野の異なる広告が表示されることもある)。Googleでの検索履歴から広告が表示されることもある[2]。 日本では2003年12月一般向けに募集を開始[3]したことでブロガーなどに広まり急速にシェアを広げた。
その他、ウェブページ内に検索の機能を提供し、検索キーワードに関連する広告を表示する検索向けAdSense、RSSフィードの記事内にAdSense広告を自動的に表示するフィード向けAdSense[4]などがある。


ということで、Google AdSenseを使用してOctopressサイト内に広告を表示してみようと思います。

Google AdSense側の設定

所有サイトのURLを追加する(任意)

所有サイトとしてサイトのURLを登録しておくことでサイト固有の広告ブロック ルールを作成するなど、サイトに関連する操作を行うことができるようになるようです。具体的には、特定広告主URLや広告ネットワーク、特定カテゴリに関わる広告を表示させたくない場合等に非表示設定をおこなうことが可能です。

Google AdSenseへGoogleアカウントにてログインし、アカウント > サイト管理の順にページを移動します。

下の画像のようなテキスト入力フォームがあるので、広告を表示させたいサイトのトップURLを入力し、サイトを追加します。

広告ユニットを作成し、コードを取得する

Google AdSenseにおける広告は広告タイプ(テキスト広告とディスプレイ広告、テキスト広告のみ、ディスプレイ広告のみ)や広告サイズ(468x60、160x600、レスポンシブ、など)を定義した広告ユニットが広告の生成単位となり、広告コードもこの広告ユニット単位で生成されます。

サイドバー向けの広告ユニットを作成します。

[広告の設定] > [コンテンツ] > [広告ユニット]までページを進め、+新しい広告ユニットをクリックします。


名前は、あとで広告ユニットを特定しやすいように一意の名前と説明を入力するといいでしょう。 今回はbuf-material_aside_336x280とします。

広告サイズは最初に表示されている推奨から選ぶと無難かもしれません。これら推奨の広告サイズはGoogle AdSense側で広告の掲載効果があったとされる広告サイズのようです。今回は336x280 レクタングル (大)を選択します。

また、モバイルで効果的な広告サイズにはモバイルのアイコン(mobile icon)が表示されます。

広告サイズに関しては、プレビューを選択することでポップアップで実際の大きさを確認できますので参考に出来ますね。


広告タイプは、テキスト広告とディスプレイ広告テキスト広告のみディスプレイ広告のみの3つから選択します。今回は推奨されているテキスト広告とディスプレイ広告を選択します。



保存してコードを取得を選択し、コードを取得します。

Octopress側の設定

今回は、広告をサイドバーに表示してみようと思います。

Octopressではサイドバーのコンテンツはセクションごとにsource/_includes/custom/asides/ディレクトリ以下にHTMLファイルを用意し、_config.yml内のdefault_asides:に表示させたいファイル名をリストで持つことになっています。

サイドバーに表示するHTMLの準備

source/_includes/custom/asides/google_adsense_336x280.htmlとして作成します。この時、Octopress側で1つのセクションであることを定義するために一番外枠として<section>と</section>で括るようにします。

source/_includes/custom/asides//google_adsense_336x280.html
1
2
3
4
5
6
7
8
9
10
11
<section>
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- buf-material_aside_336x280 -->
<ins class="adsbygoogle"
     style="display:inline-block;width:336px;height:280px"
     data-ad-client="ca-pub-XXXXXXXXXXXXXXXX"
     data-ad-slot="XXXXXXXXXX"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
</section>

_config.yml の設定

_config.ymldefault_asides:google_adsense_336x280.htmlを追記します。この広告はサイドバーの最上段に表示させたいので、default_asides:リストの1番上に記述します。

_config.yml
1
2
3
4
5
6
default_asides: [
    custom/asides/google_adsense_336x280.html,
    asides/recent_posts.html,
    custom/asides/category_list.html,
    custom/asides/tag_cloud.html,
]

静的ファイルの再生成とデプロイ

静的ファイルを再生成します。

1
2
3
4
rake generate

## ローカル環境で確認する場合はpreviewタスクも実行します
rake preview

GitHub Pagesへデプロイします。

1
rake deploy

確認

GitHub Pagesへアクセスした際に表示されるHTMLコードを確認し、<aside>タグ内に以下のscriptコードが組み込まれていれば設定できています。

1
2
3
4
5
6
7
8
9
10
11
<section>
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- buf-material_aside_336x280 -->
<ins class="adsbygoogle"
     style="display:inline-block;width:336px;height:280px"
     data-ad-client="ca-pub-XXXXXXXXXXXXXXXX"
     data-ad-slot="XXXXXXXXXX"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
</section>

Google Analytics


Google AnalyticsはGoogleが提供するアクセス解析ツールです。

サイトページ内にトラッキングコードと呼ばれるJavaScript コードを埋め込み、訪問者がサイトへアクセスした際の閲覧情報がGoogle Analyticsサーバへ送信される仕組みです。Webサーバのアクセスログ等を解析する等とは違い、開発者はこのトラッキングコードを埋め込むだけでアクセス解析ツールを利用できるという手軽さと、様々なアクセス情報を取得・閲覧できることが特徴です。

Octopressの場合、このトラッキングコードの大枠のコードがテーマのテンプレートHTMLファイルとして用意されているケースがあります。このような場合には_config.ymlgoogle_analytics_tracking_id:という箇所にトラッキング IDを記述するだけです。

トラッキング IDとはUA-000000-01のような文字列で、データの送信先となるアカウントやプロパティを Google アナリティクス側で特定するためのIDです。

トラッキングIDの取得

先述したトラッキング IDを取得します。

Google AnalyticsからGoogleアカウントでログインし、アナリティクス設定 > 管理 > 新しいアカウント の順にアクセスし、サイト情報を登録してトラッキングIDを取得します。

取得したトラッキングIDを設定

Octopressでは既にGoogle Analytics用のテンプレートHTMLが用意されているテーマもあり、デフォルトのClassicや先日変更したoctostrap3でも同様です。

### Octopress Themesに組み込まれているGoogle Analyticsテンプレート

octopress
└── .themes
    ├── octostrap3
    |   └── source
    |       └── _includes
    |           └── google_analytics.html
    |
    └── classic
        └── source
            └── _includes
                └── google_analytics.html

従って、設定は_config.ymlgoogle_analytics_tracking_id:の項に先ほど取得したトラッキングIDを記述して静的ファイルを再生成するだけでいいようです。

_config.yml
1
google_analytics_tracking_id: UA-54XXXXXX-1

静的ファイルの再生成とデプロイ

静的ファイルを再生成します。

1
2
3
4
rake generate

## ローカル環境で確認する場合はpreviewタスクも実行します
rake preview

GitHub Pagesへデプロイします。

1
rake deploy

確認

GitHub Pagesへアクセスした際に表示されるHTMLコードを確認し、HEADタグ内に以下のscriptコードが組み込まれていれば設定できています。

1
2
3
4
5
6
7
8
9
10
   <script>
    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

    ga('create', 'UA-54XXXXXX-1', 'auto');
    ga('send', 'pageview');

  </script>

Google Analyticsのアクセス解析結果が表示させるまで24時間程度かかるので表示されるのを待ちましょう。

デフォルトテーマ

Octopressではデザインテーマをinstallタスクにてインストールします。デフォルトでインストールされるテーマはclassicです。

installタスクの動作を理解する

Octopressでテーマを適用するinstallタスクの動作を見てみようと思います。

下記コードはOctopressのRakefileに記述されたinstallタスクです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
task :install, :theme do |t, args|
  if File.directory?(source_dir) || File.directory?("sass")
    abort("rake aborted!") if ask("A theme is already installed, proceeding will overwrite existing files. Are you sure?", ['y', 'n']) == 'n'
  end
  # copy theme into working Jekyll directories
  theme = args.theme || 'classic'
  puts "## Copying "+theme+" theme into ./#{source_dir} and ./sass"
  mkdir_p source_dir
  cp_r "#{themes_dir}/#{theme}/source/.", source_dir
  mkdir_p "sass"
  cp_r "#{themes_dir}/#{theme}/sass/.", "sass"
  mkdir_p "#{source_dir}/#{posts_dir}"
  mkdir_p public_dir
end

コードを見ても分かる通り、installタスクで実行していることは以下の6つの事だけで、とてもシンプルな動作です。#{theme}はデフォルトではclassicが代入される変数です(上記コードの6行目)。

  1. sourceディレクトリを作成
  2. .themes/#{theme}/sourceディレクトリ以下のファイルやディレクトリを再帰的にsourceディレクトリにコピー
  3. sassディレクトリを作成
  4. .themes/#{theme}/sassディレクトリ以下のファイルやディレクトリを再帰的にsassディレクトリにコピー
  5. source/_postsディレクトリを作成
  6. publicディレクトリを作成

テーマのインストール

テーマのインストールに必要な作業は以下の3つだけです。

  1. .themesディレクトリ以下にインストールしたいテーマをプロジェクトごとコピーする
    • .themes/octostrap3/のようになる
  2. installタスクをインストールしたいテーマを明示して実行する
    • rake 'install[octostrap3]'のようになる
  3. generateタスクを実行して静的ファイルを生成する

octostrap3テーマをインストールする

今回はOctostrap3をテーマとしてインストールしてみます。

octostrap3プロジェクトを.themesディレクトリ以下にcloneしてきます。

1
git clone https://github.com/kAworu/octostrap3 .themes/octostrap3

.themesディレクトリ以下はこのようなディレクトリ構成になるはずです。

### octostrap3テーマをローカル環境にcloneした状態
octopress
└── .themes/
    ├── classic
    └── octostrap3

Octopressのinstallタスクをテーマを指定して実行

1
rake 'install[octostrap3]'

Octopressのgenerateタスクを実行して静的コンテンツを生成

1
rake generate


これでサイトのデザインテーマをoctostrap3に変更できました!


と思ったらサイドサイドメニューのoctopress-tagcloud プラグインで生成されているulタグのデザインがoctostrap3に合っていない...


これはoctopress-tagcloudプラグインをインストールした際に置いたテンプレートファイルの書き方を修正することで対応できます。

octopress-tagcloud プラグイン向けのHTMLテンプレートファイルを修正

プラグインを利用してコンテンツを生成している場合、source/_includes/custom/asidesディレクトリ以下にコンテンツ生成用のHTMLテンプレートファイルを配置していると思います。

今回、デザインテンプレートをclassicからoctostrap3に変更したので、追加したテンプレートファイルのdivなどのブロック構成、classidなどのデザインに関わるコードもoctostrap3のデザインに合う様に修正しようと思います。

ちょうど、octostrap3のブログページにCategory List Asideという記事でサイドメニューにカテゴリーリストを追加するためのテンプレートコードが掲載されていましたのでそのまま利用させて頂きます。

修正対象ファイル

以下のディレクトリツリーにある2つのHTMLファイルを修正します。

### octostrap3導入にあたって修正するテンプレートファイルのパス
octopress
└── source/
    └── _includes
        └── custom
            └── asides
                ├── category_list.html
                └── tag_cloud.html

修正

source/_includes/custom/asides/category_list.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<section class="panel panel-default">
  <div class="panel-heading">
    <h3 class="panel-title">Categories</h3>
  </div>
  <div class="list-group">
    {% for category in site.categories %}
    {% capture category_url %}//{% endcapture %}
    <a class="list-group-item " href="">
        <span class="badge"></span>
        
      </a>
    {% endfor %}
  </div>
</section>
source/_includes/custom/asides/tag_cloud.html
1
2
3
4
5
6
<section class="panel panel-default">
  <div class="panel-heading">
    <h3 class="panel-title">Tag cloud</h3>
  </div>
  <span id="tag-cloud">{% tag_cloud counter:true %}</span>
</section>


簡単でした!

デフォルトのサイドメニュー

Octopressをインストールした直後は、サイドメニューはRecent Postsのみです。


そこでOctopress向けに公開されているプラグインを使ってサイドメニューにカテゴリーリストとタグクラウドを実装します。

プラグイン

jekyllには、特定コンテンツをHTMLとして生成してあなたのサイトに表示させるためのプラグインという仕組みを持っています。そして同時に、多くのプラグインが作成・公開されています。

imathis/octopressjekyllのためのフレームワークであり、静的コンテンツ生成にはjekyllを使用しているため、もちろんプラグインを導入することが可能です。

tokkonopapa/octopress-tagcloud プラグインのインストール

tokkonopapa/octopress-tagcloudのソースコードをcloneして、jekyllプラグインインストール作法に準じてファイルを配布します。

1
2
3
git clone git@github.com:tokkonopapa/octopress-tagcloud.git
cp -p octopress-tagcloud/plugins/tag_cloud.rb plugins/
cp -p octopress-tagcloud/source/_includes/custom/asides/* source/_includes/custom/asides/

jekyllの設定ファイル_config.ymlにtokkonopapa/octopress-tagcloud プラグインで生成する静的ファイルをサイドメニューのコンテンツとして使用するための設定を記述します。

Octopressの_config.ymldefault_asides:から始まる行があります。default_asides:はサイドメニューに表示するHTMLファイルを配列で記述していきます。

tokkonopapa/octopress-tagcloud configuration (_config.yml)
1
2
3
4
5
default_asides: [
    asides/recent_posts.html,
    custom/asides/category_list.html,
    custom/asides/tag_cloud.html
]

静的ファイルを生成してWebサーバを起動します。

1
2
3
4
rake preview

# GitHub Pages等でホスティングさせている場合はデプロイコマンドも実行しましょう
rake deploy

これでサイドメニューに以下画像のようなカテゴリーリストとタグクラウドが表示されたはずです。


簡単でした!

OctopressGitHub pagesでホスティングさせているのですが、GitHubレポジトリへのdeployタスクrejectedとなって失敗してしまうことがあります。

1
2
3
4
5
6
7
8
9
10
11
## Pushing generated _deploy website
Enter passphrase for key '/home/maehachi08/.ssh/id_rsa':
To git@github.com:buf-material/buf-material.github.io.git
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'git@github.com:buf-material/buf-material.github.io.git'
To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes before pushing again.  See the 'Note about
fast-forwards' section of 'git push --help' for details.

## Github Pages deploy complete
cd -

暫定対処

他にも解決方法があるかもしれませんので暫定と思っています。

OctopressのRakefileに記述されているdeployタスク内で実行されているpushタスクをforceオプションで実行します。

git pushコマンドのremoteレポジトリ名の頭に+を付加することでforceオプションと同じ効果を付加できるようです。

diff of Rakefile
1
2
3
4
5
6
7
8
9
10
11
--- a/Rakefile
+++ b/Rakefile
@@ -265,7 +265,7 @@ multitask :push do
     puts "\n## Committing: #{message}"
     system "git commit -m \"#{message}\""
     puts "\n## Pushing generated #{deploy_dir} website"
-    Bundler.with_clean_env { system "git push origin #{deploy_branch}" }
+    Bundler.with_clean_env { system "git push origin +#{deploy_branch}" }
     puts "\n## Github Pages deploy complete"
   end
 end

いきなりですが、ブログを開設したいと思いました。

VimやMarkdownの勉強も兼ねることができるので、Octopress + GitHub Pagesで書いてみることにします。

Octopress

http://octopress.org/

Octopressとは、mojombo/jekyllという静的ファイルジェネレータのためのフレームワークです。

jekyllがMarkdownでの記事作成に対応しているのでエンジニアの方で利用されている方が多いようです。

  1. HTML5,レスポンシブデザイン対応
    • デフォルトのテンプレートデザインで既にレスポンシブデザイン対応
  2. Compass,Sassを用いたデザイン
  3. 記事の新規作成やローカルレビューなどの操作はrakeタスクに纏まっていてシンプル
  4. ローカルで作成した記事を反映させる方法は、Github pagesRsyncを利用
    • Github pagesの場合はgithubへpushして更新
  5. POW,WEBrick,thinなどのRackサーバをサポート
  6. カラースキームとしてsolarizedを採用することで美しいシンタックスハイライトを実現
  7. Markdownで記事を作成可能

GitHub Pages

https://pages.github.com/

GitHub Pagesとは、username.github.ioというレポジトリに静的コンテンツを置くことでWebサイトとして公開できるものです。 WebサイトのデフォルトURLはレポジトリ名と同じhttp://username.github.ioとなります。 ちなみに、usernameは自分のGitHubアカウント名に置き換えてください。

GitHub PagesとしてWebページを作成することでコンテンツをGit管理にできるほか、GitHubレポジトリに置けることでバックアップとしての意味合いも果たします。

そして、GitHub Pagesでは静的ファイルジェネレータのmojombo/jekyllを使ったブログ作成が可能なので、Octopressもインストール可能なのです。

Octopressをローカル環境にインストール

今回の最終目標はGitHub PagesでOctopressのエントリー記事を表示させることですが、記事作成などの主な操作はローカル環境で行う必要があります(GitHubレポジトリの内容を直接操作することはできない)。ローカル環境で記事作成などの操作を行った後にGitHubへPushすることでGitHub Pagesに反映させるのです。

Octopressのソースコードをgit cloneでローカル環境に持ってきます。 ローカル環境側のRubyバージョンが1.9.3以上の必要があるので、rbenvrvmなどでインストールしておきます。

1
2
git clone git@github.com:imathis/octopress.git username.github.io
cd username.github.io

gemモジュール群をインストールします。私の環境では、Could not find a JavaScript runtimeエラーが発生するのを防ぐために、therubyracerプラグインも一緒にインストールします。

Gemfileに追記します。

Gemfile
1
2
# for "Could not find a JavaScript runtime" Error
gem 'therubyracer'

Gemfileに記述されているGemモジュール、および依存関係のあるGemモジュールをインストールします。

1
bundle install

rake installコマンドを実行してOctopress初期セットアップとしてデフォルトテーマ用のファイルをJekyllの静的コンテンツ生成パスにコピーします。 rakeタスク実行時の標準出力をそのまま記載しているのでmkdircpはrakeタスク内で実行済みです。

1
2
3
4
5
6
7
8
$ bundle exec rake install
## Copying classic theme into ./source and ./sass
mkdir -p source
cp -r .themes/classic/source/. source
mkdir -p sass
cp -r .themes/classic/sass/. sass
mkdir -p source/_posts
mkdir -p public

この段階で初期ページの表示確認は可能なはずですのでrake previewコマンドを実行して、ローカル環境でWebページを公開します。

rake previewコマンドを実行することでRakefile内のpreviewタスクを実行します。previewタスクではjekyll build --watchコマンドを実行して静的コンテンツをジェネレートしつつ、以降の変更を監視し続けます。変更を検知すると再ジェネレートを自動実行してくれます。そしてrackupコマンドを実行し、TCPポート4000番でWEBrickサーバを起動します。

ここでもrake previewタスクの実行時の標準出力を(_config.ymlパス以外は)そのまま記載します。

1
2
3
4
5
6
7
8
9
10
11
12
13
$ bundle exec rake preview
Starting to watch source with Jekyll and Compass. Starting Rack on port 4000
[2014-07-22 01:08:53] INFO  WEBrick 1.3.1
[2014-07-22 01:08:53] INFO  ruby 2.1.0 (2013-12-25) [x86_64-linux]
[2014-07-22 01:08:53] INFO  WEBrick::HTTPServer#start: pid=4585 port=4000
Configuration file: /path/to/username.github.io/_config.yml
>>> Change detected at 01:08:54 to: screen.scss
            Source: source
       Destination: public
      Generating...
                    done.
 Auto-regeneration: enabled
identical public/stylesheets/screen.css

ブラウザでhttp://localhost:4000(localhostの部分はローカル環境のIPアドレスに置き換えてください)にアクセスすると以下のような初期ページが確認できます。

Octopressで指定可能なrakeタスク

Octopressをインストールする際にrake installコマンドやrake previewコマンドを実行しましたが、rakeコマンドの後ろに指定したサブコマンドはRakefileに定義されたタスクに対応しています。

指定可能なrakeタスクはrake -Tコマンドで確認できます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ bundle exec rake -T
rake clean                     # Clean out caches: .pygments-cache, .gist-cache, .sass-cache
rake copydot[source,dest]      # copy dot files for deployment
rake deploy                    # Default deploy task
rake gen_deploy                # Generate website and deploy
rake generate                  # Generate jekyll site
rake install[theme]            # Initial setup for Octopress: copies the default theme into the path of Jekyll's generator
rake integrate                 # Move all stashed posts back into the posts directory, ready for site generation
rake isolate[filename]         # Move all other posts than the one currently being worked on to a temporary stash location (stash) so regenerating the site happens much more quickly
rake list                      # list tasks
rake new_page[filename]        # Create a new page in source/(filename)/index.markdown
rake new_post[title]           # Begin a new post in source/_posts
rake preview                   # preview the site in a web browser
rake push                      # deploy public directory to github pages
rake rsync                     # Deploy website via rsync
rake set_root_dir[dir]         # Update configurations to support publishing to root or sub directory
rake setup_github_pages[repo]  # Set up _deploy folder and deploy branch for Github Pages deployment
rake update_source[theme]      # Move source to source.old, install source theme updates, replace source/_includes/navigation.html with source.old's navigation
rake update_style[theme]       # Move sass to sass.old, install sass theme updates, replace sass/custom with sass.old/custom
rake watch                     # Watch the site and regenerate when it changes

記事を投稿する

新しい記事を投稿するためにはrake new_post[title]コマンドを実行します。title部分は任意のタイトル文字を記述します。英字以外だとうまく認識できないケースが考えられるので、ここでは英字で指定します。

1
rake new_post[test_post]

rake new_post[test_post]コマンドでsource/_posts/yyyy-mm-dd-test-post.markdownというファイルが作成されます。

1
vim source/_posts/yyyy-mm-dd-test-post.markdown

テストのために本文を1行だけ追記しました。

source/_posts/yyyy-mm-dd-test-post.markdown
1
2
3
4
5
6
7
8
9
---
layout: post
title: "test_post"
date: yyyy-mm-dd 00:00:00 +0900
comments: true
categories:
---

テスト投稿です

静的ページを生成します。

1
rake generate

サーバを立ち上げます。

1
rake preview

ブラウザでhttp://localhost:4000(localhostの部分はローカル環境のIPアドレスに置き換えてください)にアクセスします。

OctopressをGithub Pagesで表示させる

今までローカル環境で編集してきたOctopressコードを新規作成した記事と共にGitHubにpushします。

GitHubレポジトリ作成

GitHubの新規レポジトリ作成ページにアクセスします。

https://github.com/new

Repository nameusername.github.io(usernameは自分のGitHubアカウント名)を指定し、Create repositoryボタンをクリックします。

ローカル環境にてgitレポジトリの作成

OctopressでGitHub Pagesを利用する場合のgitレポジトリ作成にはsetup_github_pagesという専用のrakeタスクが用意されています。

rake setup_github_pagesコマンドを作成したレポジトリのURLと共に実行します。

  • レポジトリのURL例
    • git@github.com:your_username/your_username.github.io.git
    • https://github.com/your_username/your_username.github.io
1
rake setup_github_pages[git@github.com:username/username.github.io.git]

GitHub Pagesへ反映

Octopressで記事などをGitHubへpushする時にはdeployタスクを利用します。

1
rake deploy

GitHubにpush後10分程度待つと、http://username.github.ioで先ほどまでローカル環境で表示できていたOctopressページを表示させることに成功しました。

ソースをBitbucketで管理

rake deployコマンドでは、GitHub上に作成されたレポジトリのmasterブランチにmojombo/jekyllの静的コンテンツのみがpushされます。そしてGemfile,Rakefile,sassディレクトリ,sourceディレクトリがレポジトリ管理になっていません。

Deploying to Github Pagesでは、同一レポジトリにsourceブランチを作成してソースをcommit、pushするように説明していますが、ソースは公開する必要はないのでBitbucketで管理します。

Bitbucketに新規レポジトリを作成

Bitbucketの新規レポジトリ作成ページにアクセスします。

https://bitbucket.org/repo/create

今回はoctopressという名前のレポジトリ`を作成しています。

ソースをコミット

Gemfile,Rakefile,sassディレクトリ,sourceディレクトリなどをレポジトリにコミットします。

1
2
git add -A
git commit -m 'Modify config. Add source and sass'

Bitbucketに作成したレポジトリへpush

1
2
git remote add bitbucket git@bitbucket.org:username/octopress.git
git push -u bitbucket source

まとめ

Octopressのインストール

  1. https://github.com/imathis/octopress からソースコードをclone
  2. rake installを実行して初期セットアップ
  3. rake new_post['blog_title']で新規記事を投稿
  4. rake generateで静的ページを生成
  5. rake previewでlocalhostの4000番ポートでWebサーバを起動

GtiHub PagesでOctopressで生成した静的ページを表示

  1. https://github.com/new で新規レポジトリを作成
    • Repository nameはusername.github.io(usernameは自分のGitHubアカウント名)
  2. rake setup_github_pagesでGitHub pagesを利用するための初期セットアップ
  3. rake deployでGitHubレポジトリへpush

Bitbucketでソースコード管理

  1. https://bitbucket.org/repo/create で新規レポジトリを作成
  2. git add -Agit commitでソースコードをコミット
  3. git remote addでBitbucketレポジトリをremote先として追加
  4. git pushでBitbucketレポジトリにpush