Bitissues を RubyMotion で書き直してリリース

Objective-C で作っていた Bitbucket Issues の iOS クライアント『Bitissues』を RubyMotion で書き直した。 Apple の審査もすんなり通過。 これが初めてリリースする RubyMotion 製アプリになる。

f:id:griefworker:20140415195847p:plain

今回のリリースで、ようやくイシューのステータスを変更できるようになった。 あと、Pull To Refresh や AutoPagerize を実装したり、FontAwesome や IonIcons を使って、 今どきな UI に近づけてみた。

せっかく Objective-C で作っていたのに、なぜ RubyMotion で書き直したかというと、 Objective-C では開発を続けるモチベーションが沸かなかったから。

Objective-C は着々と進化して記述が簡単になっているし、 Xcode の入力補完やデバッガのおかげで生産性は高い。 ただ、Objective-C がどうも肌に合わなかった。 ならばいっそ、書いてて不思議と楽しく感じる RubyMotion で書き直してしまえ、となって今に至る。

この「楽しい」とか「合う」といった肌感覚は重要だと思っていて、プライベートプロジェクトにとっては死活問題。モチベーションが沸かずそのまま頓挫、なんてことになりかねないし。

まぁ、RubyMotion の更新費用1万円を捻出できずに、開発を継続できなくなる可能性はある。 そのときはソースコードを公開するなり、また Objective-C に戻るなりすればいいか。 RubyMotion と Objective-C 間で SDK やライブラリの知識を共有できるのは幸い。

エスプレッサメンテ イリー

週末天神に繰り出して、春物の服を求めてショップを渡り歩き、さすがに歩き疲れたので一休み。地下鉄天神駅出てすぐにある『エスプレッサメンテ イリー』に入ってみた。

アイスカプチーノとティラミスのセットを注文。ティラミスは一押しみたいで、前から気になっていた。

f:id:griefworker:20140413182341p:plain

アイスカプチーノのアップ。

f:id:griefworker:20140413182408p:plain

デパートはどこも暑かったんで、冷たいカプチーノで生き返った。

あとティラミス。

f:id:griefworker:20140413182427p:plain

ティラミスは表面がビスケットなんで固い。マスカルポーネチーズのクリーム部分も思っていたよりしっかりした食感。想像していたよりも、ビターな味だった。

関連ランキング:カフェ | 西鉄福岡駅(天神)天神駅天神南駅

川端どさんこ

急遽夜に外食することになったんで、川端商店街に昔からある『川端どさんこ』に行ってみた。

f:id:griefworker:20140413143159p:plain

特製味噌ラーメン。ラーメン価格高騰が問題視される昨今、特製で 650 円は比較的リーズナブル。スープは味噌だけどあっさりめ。

f:id:griefworker:20140413143429p:plain

やきめし。500円。正直予想以上のボリューム。半分でよかったな。やりすぎた。半分サイズとのセットがあれば。

関連ランキング:ラーメン | 中洲川端駅呉服町駅祇園駅

UITableView のセパレーターの描画がおかしい

ios

まずはこれを見て欲しい。

f:id:griefworker:20140409194344p:plain

UITableView のセパレーターがおかしなことになっている。 左端に隙間が開いているものもあれば、左端までぴったり線が描画されているものもある。 左端までぴったり線が描画されているものは、線も少し太い。

UITableView の separatorStyle を UITableViewCellSeparatorStyleNone にしても、左端まで達している線は残る。 カスタムセルを使っているけど、border を設定してはいない…。

ほとんど諦めかけていたんだけど、ふと 「行の高さがおかしいのかも」と思って、行の高さをコンソールに出力してみたら

123.789993286133
123.789993286133
123.789993286133
123.789993286133
123.789993286133
123.789993286133

案の定、浮動小数点数ばっかり。 試しに round で小数点以下を切り上げてみたら

f:id:griefworker:20140409194418p:plain

変な線が表示されなくなった! 原因に気付くまでに2日かかってしまったよ…。解決してよかった。

RubyMotion でリポジトリに含めたくない設定を外部ファイルに抜き出す

Web API の consumer_key と consumer_secret のような、 人に知られたくないキーは Git リポジトリに含めたくない。 そこでキーを git リポジトリ管理外の設定ファイルに抜き出すことにした。

設定ファイルを読み込んで RubyMotion でいい感じに扱うための gem で RubyMotion Wrappers に載っているのは、motion-config-vars ていうやつ。

motion-cofnig-vars

resources/app.yml に

API_ENV:
  development:
    cosumer_key: "hogehoge"
    consumer_secret: "fugafuga"
  test:
    cosumer_key: "hogehoge"
    consumer_secret: "fugafuga"
  production:
    cosumer_key: "hogehoge"
    consumer_secret: "fugafuga"

って書いて、

bundle exec rake API_ENV=development

で実行すれば、development 以下の設定を ENV にセットしてくれる。 ただ、API_ENV を毎回指定するのが面倒。おしい。

RubyMotion Wrappers には載ってない gem

motion-mode 作者でもある ainame 氏が作った motio-my_env がある。 Watson 氏が作った motion-env-vars もある。

自分は motion-my_env を使ってる。 motion-env-vars は最近知ったのでまだ試していない。 README 読んだ感じだと、使い方同じっぽい。

motion-my_env

config/environment.yaml に設定を書いて

hatena:
  consumer_key: "hogehoge"
  consumer_secret: "fugafuga"

Rakefile 内で yaml ファイルのパスを指定する。

Motion::Project::App.setup do |app|
  # ...

  app.my_env.file = "./config/environment.yaml"

  # ...
end

するとアプリ内で

MY_ENV["hatena"]["consumer_key"] # => hogehoge

という風にアクセスできる。 YAML をパースした結果が MY_ENV 定数に格納されるようだ。

Rails + Apartment でマルチテナントな Web サービスを作る

はじめに

例えば Qiita::Team のような、企業やチーム向けに提供するマルチテナントな Web サービスの場合、 テナントを分ける方法としてぱっと思いつくのは

  • すべてのテーブルに tenant_id 列を追加し、tenant_Id で常に絞り込む
  • テナントごとにデータベースを分ける

の2つ。

このうち tenant_id 列を追加する方法だと、使うのに苦労する gem がある。 Devise とか Devise とか Devise とか。いやまぁ、default_scope でやれないことはないかもしれないけど。

テナントごとにデータベースを分ける方法なら、上手くデータベースさえ切り替えられれば、 Devise もそのまま使えるはず。

データベースを分ける方法でマルチテナントを実現するための gem に Apartment がある。

これを試してみる。

まずはサンプルプロジェクト作成

rails new multi_tenant_sample --skip-bundle

Devise と Apartment をインストール

ユーザーもテナントごとに登録したい。 Devise と Apartment を組み合わせて実現出来るか挑戦。

Gemfile に

gem "devise"
gem "apartment"

を追加し、下記のコマンドを順に実行。

bundle install --path vendor/bundle
bundle exec rails g devise:install
bundle exec rails g devise User
bundle exec rake db:migrate
bundle exec rails g apartment:install

テナントを作成

テナント情報を保存するモデルを用意する。 今回は簡略化のため、テナント名を保存するだけにしておく。

bundle exec rails g model tenant name:string

テナント情報は、デフォルトのデータベースにまとめて保存したい。 Apartment が Tenant を除外するように、config/initializer/apartment.rb を編集する。 あと、テナントのデータベース名一覧を取得するための設定も記述しておく。

# config/initializers/apartment.rb
require 'apartment/elevators/subdomain'

Apartment.configure do |config|

  # Tenant を除外
  config.excluded_models = %w{Tenant}

  # ... (中略) ...

  # rake db:migrate 時にすべてのテナントのデータベース名を取得するための設定
  config.tenant_names = lambda{ Tenant.pluck :name }
end

# Apartment でデフォルトでは、サブドメインでデータベースを切り替える
Rails.application.config.middleware.use 'Apartment::Elevators::Subdomain'

tenant_names を設定していないとマイグレーションを実行できないので、先にやっておくこと。 そして

bundle exec rake db:migrate

を実行。

無事マイグレーションが実行できたら、デフォルトのデータベースにテスト用のテナント情報を登録する。

bundle exec rails c
irb(main):001:0> Tenant.create(name:"foobar")
irb(main):002:0> Tenant.create(name:"hogefuga")

テナントを登録したあと

bundle exec rake apartment:create
bundle exec rake db:migrate

を実行すると、db 下に foobar.sqlite3 と hogefuga.sqlite3 が作成され、それぞれマイグレーションが実行される。

トップページを作成

確認用にトップページを作成する。

bundle exec rails g controller home index

トップページには登録されているユーザーの一欄を表示したいので、コントローラーとビューを下記のように修正する。

# app/controllers/home_controller.rb
class HomeController < ApplicationController
  def index
    @users = User.all if user_signed_in?
  end
end
<h1>Home#index</h1>
<% if user_signed_in? %>
  <%= link_to "logout", destroy_user_session_path, method: :delete %>

  <ul>
    <% @users.each do |user| %>
      <li><%= user.email %></li>
    <% end %>
  </ul>
<% else %>
  <%= link_to "login", new_user_session_path %>
<% end %>

ルーティングも修正。

# config/routes.rb
MultiTenantSample::Application.routes.draw do
  devise_for :users
  root "home#index"
end

ローカル環境で動作確認

Pow を使って動作確認する。Pow のインストール手順は次の記事の通り。 rbenv 使っていると、ちょっと苦労する。

Pow の準備が終わったら、‾/.pow の下に rails プロジェクトへのシンボリックリンクを作成。

cd ‾/.pow
ln -s ‾/Projects/multi_tenant_sample

『登録したテナントの名前=サブドメイン=テナントが利用するデータベースの名前』になっているので、 ブラウザで http://foobar.multi_tenant_sample.dev/users/sign_in にアクセスしてみる。

f:id:griefworker:20140330172959p:plain

サインアップ。

f:id:griefworker:20140330173034p:plain

登録されているユーザーの一欄が表示される。

次に http://hogefuga.multi_tenant_sample.dev にアクセス。

先ほどサインアップしたユーザーでログインしてみると

f:id:griefworker:20140330173354p:plain

ログインに失敗し、ログイン画面に戻る。ちゃんとデータベースが切り替わっているみたいだ。

こちらでもサインアップ。

f:id:griefworker:20140330173530p:plain

ユーザー一欄には、サインアップしたユーザーだけが上がっている。

まとめ

Apartment を使うことで、テナントごとにデータベースを分け、 サブドメインで切り替えることができた。 Devise に Apartment を組み合わせることで、テナントごとにユーザーを保存するのもうまくいった。

今後、Rails でマルチテナントな Web サービスを作るときは、まず Apartment を使うことにしよう。

HTML5テクニックバイブル

ジュンク堂の店頭で見つけたので購入してみた。 ネットで話題に上がっていない気がするけど、 ただ単に自分のアンテナに引っかかっていないだけなんだろうか。

本書は簡単に言うと、HTML5 で出来ることを網羅した逆引き辞典。 図やサンプルコードが豊富で、手元に置いておく参考資料としては申し分ない。 サンプルコードではところどころ、Yahoo!エンジニアのテクニックを垣間見ることができて勉強になった。

HTML5 の機能を手っ取り早く把握したい人にオススメだと思う。 実際、HTML5 で何が出来るか調べようとずっと思っていて、結局今まで調べていなかったので、ネットで情報を探しまわる手間が省けて助かった。

HTML5 テクニックバイブル
HTML5サポーターズ
技術評論社 (2014-01-04)
売り上げランキング: 299,136