Rails5でnamespace以下のxxx_root_pathヘルパーが定義されなかったので回避した
Rails 5.0.0.1を使って開発中、Rails4のころのようにroutes.rb
に書いたものが思ったように動かなかったのでメモしておきます。
以下のようなroutes.rb
を書いて、ただのルート(/
)とadmin配下のルート(/admin/
)を定義します。
Rails.application.routes.draw do root 'home#index' namespace :admin do root 'home#index' end end
そうするとViewではroot_pathやadmin_root_pathといったヘルパーメソッドが使えるはずですが、rake routesなり、Routing Errorのページなりで定義済のURLを一覧してみると、、
このように admin_root_pathがありません。Viewで呼ぶとエラーとなります。
この辺の処理をしているのはactionpack内のActionDispatchあたりです。少し中を追いかけてみたのですが、admin_root_pathのときに想定しているところを通っていないことはわかったものの、根本的な原因を突き止めるには時間がかかりそうだったのでやめて回避策に逃げました。
要はそのrouteの名前が付けばいいので、admin配下のrootところにas: :root
と書いてあげればOK。
namespace :admin do root 'home#index', as: :root end
これでadmin_root_pathが使えるようになりました。
Hello, RxSwift #iOSDC
2016/08/20に開催されたiOSDCに参加してきた。浜松市からの移動なので前日はソニックガーデンの自由が丘ワークプレイスに宿泊しての参加。自由が丘→練馬は乗り換え無しで行ける奇跡の立地。楽しく参加できた。スタッフも大勢いた。開催ありがとうございました。
色々感想があるのでそれは別途書くかもしれない。今日は色々聞いた中でもishkawaさんのRxSwiftの発表を見てRxSwiftに興味を持ったことと、会場で質問もさせてもらったのでその部分を試しがてらちょっと検証してみようと思ったので半年ぶりぐらいに投稿する。
今回は発表スライドにもあった例を使ってみることにする。複数のテキストフィールドとボタンがあって、ボタンを押したら2つのフィールドの値を結合してラベルに表示するというもの。
http://blog.ishkawa.org/talks/2016-08-20-iosdc/#/19
まずはこの例をそのまま実装することにした。なお、今回はRxSwift 2.6.0を使用した。
import UIKit import RxSwift import RxCocoa class ViewController: UIViewController { @IBOutlet weak var textField1: UITextField! @IBOutlet weak var textField2: UITextField! @IBOutlet weak var label: UILabel! @IBOutlet weak var button: UIButton! let disposeBag = DisposeBag() override func viewDidLoad() { super.viewDidLoad() Observable .combineLatest(textField1.rx_text, textField2.rx_text) { "\($0) \($1)" } .sample(button.rx_tap) .bindTo(label.rx_text) .addDisposableTo(disposeBag) } }
動かしてみるともちろん想定した通りに動く。
このようなコードのときに、「combineLatestに渡すclosureはUITextFiledのテキストが変わる度に毎に呼ばれてしまうのでパフォーマンス的によろしくないこともありますよね?」という点を質問した。それに対するishkawaさんの回答はざっくり要約すると「多分毎回呼ばれるのでそういうこともあるでしょう、でもRxSwiftで制限する仕組みもあるはずです」という感じだった。
ということで2点を試してみようと思う。
まずはクロージャはテキスト変更の度に毎回呼ばれるか、という点。適当にprintして試したところ、次のようになった。
やはりクロージャは都度呼ばれているようだ。なのでこの部分で少々重たい処理をしてしまうと操作する人にはもたつくような印象を与えてしまうことになる。
なので次にここを改善する方法を考えてみる。combineLatest
したストリームをsample
することで最新の1つを使うことにしているところの順序を逆にすることで、テキスト変更の度にcombineLatest
のクロージャが呼ばれることがないので、もう少しマシなのかもしれない。つまり、テキストフィールドの更新をsample
して、それらをcombineLatest
するといった感じか。
コードにすると、こう。
let field1 = textField1.rx_text.sample(button.rx_tap) let field2 = textField2.rx_text.sample(button.rx_tap) Observable .combineLatest(field1, field2) { print("called") return "\($0) \($1)" } .bindTo(label.rx_text) .addDisposableTo(disposeBag)
これならprint("called")
のところはボタンをタップしたときにしか呼ばれない。あまり意味のあるサンプルコードではないので適切かどうかもよくわからないが、一応呼ばれる回数は減らせた。
他にもthrottle
やdebounce(throttleの別名)
など一定時間内のものを無視するようなオペレーターも存在するけど、今回の例はボタンをタップするその直前に届いているイベントが欲しいので時間で制御するのは適さない。他の要件なら時間制御も良さそうだ。
こういったオペレーターには色々あって、↓のドキュメントに一覧があるので困ったときは読んでみたいと思っている。
というわけで、RxSwiftの世界へ一歩足を踏み入れた話でした。
Macでアプリが起動しないときはコンソール.appを見るとわかるかも
先日、仕事中ヘビーに使っている常駐アプリ達が立ち上がらない現象に遭遇した。とても困ったので一旦仕事の手を止めて復旧努めることにした。
といっても起動時に何かエラーがでるわけでもなんでもなくて、普段使っているランチャーAlfredから起動しようとしても何の音沙汰もなく、最初は途方にくれていた。 一旦落ち着いて、じゃあログでも見るかと思い立ったがログを見る方法がわからない。
しばらく調べてコンソール.appで見られるよという記述にあたったことでコンソールの存在を思い出し、ログを確認することができた。
コンソール.appはアプリケーション→ユーティリティの中にある。
コンソールを起動すると色々なシステムログが流れていることがわかる。
僕の場合は起動しないアプリを起動しようとしたときに右側のエリアに新しいログが現れた。
どのアプリで試しても同じようなエラー Service exited with abnormal code: 173
が出るのできっと同じ理由なんだろうなということがわかった。
では、ということでこのエラーメッセージで検索して調べてみたものの、これといった答えがない。 クリーンインストールで直ったよ!っていう人もいたけれど、それはちょっとね。
いろいろ探す中で「AppStoreの何かが期限切れでうんぬん」と言っている人がいた(英語だったし、サイトを忘れたのでうろ覚えです)。
起動しないアプリたちをよく見てみると、こいつらもAppStore経由でインストールしているアプリ達だということがわかったので とりあえず再インストールだろ、とやってみたら見事解決。
ということでした。
一応コンソール.appに助けられたというわけ。何もエラーが出てなかったらコンソールを使ってみたらどうでしょうか。
Railsなどで無料から使えるエラー通知サービス Rollbar
Railsなりスマホなりでアプリケーション作ったらAirbrakeとかBugsnagとかのエラーハンドリング用のサービスを使って不具合を検知できるようにするよね。
この手のサービスはやはり有料のところが多くて、個人用のアプリケーションとしてはコスト的に使いにくい。無料で使えるものでerrbitというairbrakeクローンみたいなものもあるんだけれど、自分でホストするのはそれはそれで面倒なので敬遠してました。
でも先日、自分のRailsアプリでエラーがでてついにログを見るのが面倒になって本気出して探したら無料で使えるのがありました。
それがこのサービス、Rollbar。
ざっと導入した感じ、十分使えるなという感じがしています。
ユーザー登録やプロジェクト作成、Railsへの導入とかは書くまでもないぐらいめちゃくちゃ簡単だったので省略します。
ダッシュボードはこんな感じ。洗練されているとは言えないけど、十分!
無料版の制約は
- 月5000イベント
- データ保存は30日間
なので、個人使用なら全然問題なさそう。
お試しください。
RailsアプリにiOSクライアントをサッと作る #sgadvent
この記事はソニックガーデン Advent Calendar 2015 、6日目の記事です。
どうも大野(@xoyip)です。3日目に続いて登場させてもらいます。今日は5日目までとは少し変わって技術的なHow Toの話で、自分用の覚書でもあります。
ちなみに3日目のはこれ。
ソニックガーデンではお客さまが実現したいサービスを開発するのにRuby on Railsを使っています。PCやスマートフォンのブラウザから利用されるようなサービスを作ってきました。
ところが最近のスマートフォン普及率などから、スマートフォンのネイティブアプリケーションを用意してユーザーに使ってもらいたいというお客さまのご要望も増えてきています。社内でも開発や運用についてどうしていくかの議論が盛んになってきています。
そういう流れから今日はすでに運用しているRailsアプリケーションにiOSクライアントを作るには、という話をサンプルコードで簡単に紹介できればと思います。
今回の事例
「Facebookログインを利用した既存のWebサイト(Rails)用のiOSクライアントを作りたい」というケースを考えてみます。
やらなければならないことは
この2つです。
またサンプルコードをGitHubに用意したので、RubyやXcodeがあれば実際に動かすことができます。
Railsにスマートフォン用の認証口を用意する
doorkeeperの導入
まずは外部のクライアントが認証できる仕組みをRails側に用意します。doorkeeperというgemを使うと、超簡単にOAuthプロバイダーの機能をRailsアプリケーションに追加することができます。
https://github.com/doorkeeper-gem/doorkeeper
既存のRailsアプリケーションに対して次のステップを実施すれば簡単に導入可能です。
$ gem 'doorkeeper' $ bundle $ rails generate doorkeeper:install $ rails generate doorkeeper:migration $ rake db:migrate
あとはroutes.rb
に追記すれば大体おわり。
# config/routes.rb Rails.application.routes.draw do # 他のroutes use_doorkeeper end
※設定は上のステップで生成されたconfig/initializers/doorkeeper.rb
で。色々あるので説明は省略!
OAuth Applicationの作成
先ほどのセットアップがうまくいっていれば/oauth/applications
にアクセスして次のような画面を開くことができるようになります。この画面から新しいアプリケーションを作成していきます。
必要なパラメータを入れます。名前は識別できればなんでもよくて、リダイレクトURI
にはiOS側で設定するものと同じものを入れます。今回はintegration-sample-ios://oauth-callback/ios
を使うことにしました(スキーマ以外が合っていれば、path
などは必要に応じて変えればよいです)。
追記
development環境以外ではURLスキームがhttpsでないとエラーとなります。それを回避するためにはconfig/initializers/doorkeeper.rb
でforce_ssl_in_redirect_uri false
としておけば良いです。
追記おわり
作成するとアプリケーションIDやトークンが発行されます。iOS側で使うので控えておきます。
APIを用意する
Railsアプリケーション側にJSON APIがなければ作っておきます。今回はiOSからログインできていることを確認するために、ログインしているユーザーの名前やメールアドレスを返すAPIを用意します。
まずAPI用のApplicationController
的なものを用意します。
API用のコントローラの全てのアクションでdoorkeeper_authorize!
で認証をかけて、ヘルパーメソッドcurrent_user
で認証したユーザーを得られるようにしておきます。
# app/controllers/api/api_controller.rb class Api::ApiController < ApplicationController before_action :doorkeeper_authorize! helper_method :current_user def current_user User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token end end
最後に、名前とメールアドレスを返すAPIを定義します。
# app/controllers/api/users_controller.rb class Api::UsersController < Api::ApiController def show @user = current_user end end
# app/views/api/users/show.json.jbuilder json.extract!(@user, :id, :name, :email)
これをiOSから呼び出せれば連携成功!となるわけです。
iOSクライアントを作る
iOSアプリでは起動時にログイン済みかどうかを判定し、ログイン済みであればAPIを叩いて自分の情報を表示、そうでなければログイン画面を表示という流れになるようなものを作ります。
pod install
ライブラリをいくつか使うのでそれらをインストールします。
# Podfile source 'https://github.com/CocoaPods/Specs.git' platform :ios, '9.0' use_frameworks! pod 'Alamofire', '>= 2.0' # APIを呼ぶときに pod 'SwiftyJSON', '>= 2.3' # APIのレスポンスの処理に pod 'p2.OAuth2', '~> 2.0.0' # OAuth2の認証に pod 'KeychainAccess' # トークンの保存に
※iOS9からhttpの通信で叱られるようになります。それだと開発中に困るのでApp Transport Securityの設定でhttpを許すドメインを指定してあげたほうが便利です。
※p2.OAuth2ライブラリ内のコードに、開こうとしているURLがhttpのときはassertで止まるような記述があります。あまりよろしくないですが開発中はコメントアウトしています。
URLスキームを設定する
p2.OAuth2を使った認証の流れですが、
といった感じになっています。doorkeeperで設定したリダイレクトURIは認証後にアプリに戻るために使われます。
URLスキームの設定方法はこんな感じ。
認証する
認証のところのコード(全体像はサンプルコードを見てもらったほうがよいと思います)。
var oauth2 : OAuth2CodeGrant? let settings = [ "client_id": "YOUR_APP_ID", "client_secret": "YOUR_APP_SECRET", "authorize_uri": "YOUR_SERVER_URL" + "/oauth/authorize", "token_uri": "YOUR_SERVER_URL" + "/oauth/token", "scope": "", "redirect_uris": ["integration-sample-ios://oauth-callback/ios"], "keychain": false, ] as OAuth2JSON // OAuthアプリケーションのトークンなどを使って認証用のオブジェクトを生成 oauth2 = OAuth2CodeGrant(settings: settings) // アプリ内に埋め込みでSafariViewを出す oauth2?.authConfig.authorizeEmbedded = true // 成功時 oauth2?.onAuthorize = { parameters in let json = JSON(parameters) // トークンを保存 let keychain = KeychainAccess.Keychain(service: "YOUR_BUNDLE_ID") try! keychain.set(json["access_token"].stringValue, key: "access_token") } // 失敗時 oauth2?.onFailure = { error in print(error) }
そして最初のビューが表示されたタイミングで、ここで生成したoauth2
オブジェクトを使ってログイン画面を表示します。
override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) let keychain = KeychainAccess.Keychain(service: "YOUR_BUNDLE_ID") // トークンが保存されているかどうかでログイン済みかどうかを判定する if let accessToken = try! keychain.get("access_token") { // APIを呼ぶ } else { // contextとして自身(UIViewController)を指定する Auth.sharedInstance.oauth2?.authConfig.authorizeContext = self // ログイン画面を出す Auth.sharedInstance.oauth2?.authorize() } }
最後に、認証完了後、URLスキームでアプリに戻ってきたことをoauth2
オブジェクトに教えてあげることで成功時のコールバックonAuthorize
が呼ばれます。
// AppDelegate.swift func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool { if let path = url.path { if path.hasPrefix("/ios") { Auth.sharedInstance.oauth2?.handleRedirectURL(url) return true } } return false }
なお今回はoauth2
オブジェクトを各所から参照するためにシングルトンを用いています。
APIを使う
ここまでくれば、あとは取得したトークンでAPI呼び出しをするだけです。
ApiClient.sharedInstance.get("/user", parameters: [:], onSuccess: { json in let alertController = UIAlertController(title: "ログイン成功", message: "\(json["name"])\nとしてログインしました", preferredStyle: .Alert) let defaultAction = UIAlertAction(title: "OK", style: .Default, handler: nil) alertController.addAction(defaultAction) self.presentViewController(alertController, animated: true, completion: nil) }, onFailure: { error in print(error) })
jsonにはRailsが返したid、名前、メールアドレスが入っています。アラートで表示(手抜き)してきちんと取得できるのが確認できるはずです。
ちなみにAPIクライアントはこんな感じのコードです。本当のアプリケーションではもっと汎用的に使えるような書き方をしたほうが良いですが、サンプルなのでサッと書いてしまいました。
// ApiClient.swift class ApiClient: NSObject { static let sharedInstance = ApiClient() let endpoint : String = "YOUR_SERVER_URL/api" func get(path: String, parameters: Dictionary<String, String>, onSuccess: (JSON)->Void, onFailure: (NSError)->Void) { guard let url = NSURL(string: endpoint + path) else { return } let headers = [ "Authorization": "Bearer \(Auth.sharedInstance.accessToken()!)" ] Alamofire.request(.GET, url, headers: headers, parameters: parameters).responseJSON { response in if response.result.isSuccess { if let value = response.result.value { onSuccess(JSON(value)) } } else { if let error = response.result.error { onFailure(error) } } } } }
これでiOSアプリケーションとRailsの連携ができるようになりました。ライブラリに頼りっきりではありますが、その分連携するまでをサッと作ることができます。アプリケーションそのものに時間を使ったほうがいいですからね。
何回か書いていますが、サンプルコードを見てもらったほうがわかりやすいと思います。
リモートワークを始めたら家から出なくなった話 #sgadvent
この記事はソニックガーデン Advent Calendar 2015 、3日目の記事です。
(いつもは常体メインの適当文体で書いていますが、アドベントカレンダーってことでなんとなく敬体にしてみます。)
どうも大野(@xoyip)です。ここにもTwitterにもFacebookにもどこも書いていませんでしたが、10月からソニックガーデンという会社で働いてます。
ソニックガーデンというと納品のない受託開発をしているとかRuby on Railsで開発しているとか、コードレビューをしっかりするとかリモートワークをしている人が多いとか、色々なイメージがあると思います。今回はその中でもリモートワークにフォーカスして何かを書いてみます。
リモートワーク
ソニックガーデンでは積極的にリモートワークを取り入れています。リモートワークは場所を選ばすに働くということなので、ソニックガーデンのメンバーは必ずしもオフィスで働く必要はありません。僕は静岡県浜松市に住んでいるので渋谷区にあるソニックガーデンのオフィスに通うなんてことはできず、基本的には自宅で仕事をしています。東京近郊のメンバーでも天候や家庭の事情などで出社せずに働くこともあります。
リモートワークについての詳しいことは、ちょうど今日の朝、代表の倉貫がブログを更新したところ(タイムリー!)なのでそちらもご参照ください。
僕が基本的には自宅で仕事をしているというのが今日の話の前提です。ちなみに、ソニックガーデンで仕事をする前、9月以前も月の半分近くは自宅で仕事をしていました。
リモートワークには様々な利点があり色々なところで見聞きすることもあるかと思います。。通勤にかかる移動時間を節約でき他のことに充てられるし、食事や休憩を妻や子どもと過ごすとか仕事の合間に家事やちょっとした用事をすませることもできます。
そして、仕事環境を自由にカスタマイズすることができます。幸い今住んでいるところでは仕事部屋として一部屋確保できているので、そこを目一杯使えるデスクを導入して広々と仕事をしています。デスクについては1年半ほど前にこのブログに書いたので見てみてください。
リモートワーカーの一日
僕がどのような一日を過ごしているかをタイムテーブル的に紹介します。
時刻 | やったこと |
---|---|
6:45 | 起床。朝食や家事、子どもの幼稚園の準備を妻と手分けして行う。 |
8:30 | 午前仕事開始、社長ラジオ*1を聴く。 |
11:30 | 昼食の用意、昼食。 |
12:30 | お客さまとのミーティング。 |
14:00 | 次の仕事を始める。 |
14:30 | 子どもが帰ってくる。家が少し騒がしくなる。 |
17:30 | 子どもがお腹すいたといって機嫌が悪くなる。早めの夕食! |
18:00 | もう少し仕事をする。 |
19:00 | 仕事終わり。 |
19:30 | 子どもを寝かしつける。 |
20:00 | 自分の時間。 |
子どもに合わせて仕事とプライベートを調整できているのがわかると思います。
外出していない…!?
ところで上のタイムテーブル、外出した様子はありません。朝起きてから仕事・食事・家事・子育て、全て家の中での行動です。
リモートワーク、特にコワーキングスペースやカフェなどを使わず自宅を仕事場にしている人の場合、外出することなくすべてが済んでしまうというのは移動などの無駄が省けて効率的です。
その反面、外出しないことによって外の世界との交流が少なくなるとか、体を動かさなくなってしまうというデメリットがあります。半分リモートだったのが完全にリモートになったことで、このデメリットの部分が大きいことがわかりました。
まず交流が減るという点ですが、仕事ではRemottyというツールを使って他のメンバーと顔を合わせています。慣れてしまえばコミュニケーションが足りないという感じはあまりありません。特に問題なのは体を動かさなくなることなのではと思っています。
体を動かさないことについて
どのぐらい体を動かしていないかを、1日に歩く歩数という観点でみてみます。
厚労省の健康日本21というサイトに年齢階級別にみた歩数という統計データが掲載されています。このデータによると30代男性は平均的には1日に8866歩 歩いているらしいですね。20年近く前の古いデータではありますが、この20年の間に移動手段が急激に進化したとかはないので20年経った今でもそれほど大きな差はないのではないかなと思います。
さて次はリモートワークをしていて外出無しで過ごすことが多い僕の歩数を見てみましょう。Apple Watchを使って計測している最近の1ヶ月の歩数はこんな感じでした。
この期間の平均値は1日平均3320歩。
3320歩と言うと平均的な歩数8800歩の半分にも満たない数です。実際には体を動かさないのは良くないなと意識して歩いたり走ったりするようにしているのと、休日の買い物やレジャー等で歩数が増えている日があるのとでようやく平均3000歩超えできているのであって、意識せずに過ごしていたとしたら、平均な歩数はおそらく2000歩程度になるのではないかと思います。言い換えると、ランニングして3000歩かよ、です。
2000歩と言うと統計の4分の1以下です。本当に動いていないですね。
ちなみにソニックガーデンの渋谷オフィスへ行ったときは7000歩程度でした。他にも駅への移動や乗り換えなどがあった日を見てみると、6000歩〜8000歩程度の歩数は稼げています。都心部などで電車通勤している人はよく歩いていると言えそうです。体を動かすという意味では適度な通勤は有りなのかもしれません。
対策
体を動かさなくなると身体機能が低下していきます。僕自身の感覚でも筋力や体力の低下を感じつつあります。自宅で仕事をするということは、意識して運動しなければどんどん体が弱っていく可能性がある環境に身を置いているわけです。健康的にリモートワークを続けたいのであれば、意識して歩いたり走ったりスポーツをしたりする時間を確保するしかありません。
僕の場合だと完全リモートになった10月以降、これらを実践しています。
- ランニング
- 自転車
- エアロバイク
- 散歩
始めた頃は子どもを送り出してから仕事を始めるまでの間に。最近は寒くなってきたので仕事を早めに始めてお昼前に軽く運動するのがいいかなと思って試しています。
ところで、ソニックガーデンではセルフマネジメントで仕事を進められることが一人前の条件とされています(この話は別の誰かがアドベントカレンダーで書いてくれる気がしているのでそちらにお任せしよう)。ソニックガーデンのリモートワーカーには健康面でのセルフマネジメント力も求められるというわけですね。
さて、さきほどは代表の倉貫のブログ記事を紹介しましたが、今年(2015年)の12月半ばには新しい書籍「リモートチームでうまくいく マネジメントの〝常識〟を変える新しいワークスタイル」が出る予定です。ソニックガーデンとリモートワークについての詳しいことはこちらを読んでもらったほうが良いかもしれません。

リモートチームでうまくいく マネジメントの?常識?を変える新しいワークスタイル
- 作者: 倉貫義人
- 出版社/メーカー: 日本実業出版社
- 発売日: 2015/12/17
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
*1:「リモートワーク」でチームを育てる 新しいアイデアが生まれるしくみを倉貫義人さんに聞く に社長ラジオについての記載があります
RailsアプリをHeroku→さくらVPSに移行
Herokuのプランが変わったのでRailsアプリケーションをさくらに移行した。
ここ最近Herokuの料金体系が変わってFree Dynoは18時間までしか動かせないようになったらしい。それにともなってこんなHackをする人まで出てきているようで、Freeでとりあえず動かしたいという人たちに与える影響はそれなりにあるように思える。
ssig33.com - 最悪!意地でも Heroku を無料で使う
そういう僕も家族用に自分で作ったウェブアプリケーションを運用していたんだけど、料金体系が変わる前から自分のさくらVPSに移行したいと思っていたところにこのプラン変更が来たのでこれを機にと思い移行してみることにした。
ちなみに移行したアプリケーションは、
- 普通のRailsアプリケーション
- PostgresqlがあればOK
というシンプルなものだった。Herokuで色々なアドオンを使いまくってるぜというわけではなかったのでそんなには手間ではなかったと思う。
移行先は色々な用途のために元々使っていたさくらVPSの1Gプラン。月額900円。
- CentOS 6.4
- 2 core
- 1GBメモリ
Postgresqlのインストール
別のRailsアプリケーションも動かしていたけれどそちらはMySQLを使っていたので、移行先のサーバーにはPostgresqlが入っていなかった。
インストールして初期設定を済ます。
$ wget http://yum.postgresql.org/9.4/redhat/rhel-6-x86_64/pgdg-centos94-9.4-1.noarch.rpm $ sudo rpm -ivh pgdg-centos94-9.4-1.noarch.rpm $ sudo yum install -y postgresql94-server postgresql94-devel postgresql94-contrib $ sudo /etc/rc.d/init.d/postgresql-9.4 initdb $ sudo /etc/rc.d/init.d/postgresql-9.4 start $ sudo chkconfig postgresql-9.4 on $ sudo su - postgres $ createuser -s hiromasa
rbenv
対象のアプリケーションが2.0.0-p598
で動いていたので、対象のマシンのrbenvにもそのバージョンを入れ、bundlerのインストールも済ませておく。bundlerはよく忘れる。
$ rbenv install 2.0.0-p598 $ rbenv local 2.0.0-p598 $ gem i bundler
Passenger
これまで動かしていたRailsアプリケーションは全部Ruby1.9.3系で動いていたが、今回Ruby2系も導入したことにより、Passengerも使い分けなければいけないことになった。
幸い、それを指南してくれる記事があったのでまんまこれと同じようにやったら使い分けることができた。よかった。
本当に助かりました。ありがたい。
ここまででサーバー側は大体OKになったと思う。
デプロイ
Herokuの恩恵の一つにデプロイの簡単さがあげられる。しばらく自前でのデプロイをしてこなかったため、いざ自分でやろうとするとものすごく面倒だということを思い出した。
Capistrano
2年前にちょちょっと使っていたCapistranoは3系になって色々進化していた。一応3系がベータのときに使っていたことがあり、そのときのデプロイスクリプトも残っていたので、今回のデプロイもそれを参考にすれば楽勝だろうとタカをくくっていたが、変なところで動かなくてハマった。
Herokuからさくらに移行しようとして久しぶりにCapistrano使ったらかなり辛い。まったくデプロイできない…
— hiromasa (@xoyip) August 27, 2015
エラーの内容を残しておくのを忘れたのでうろ覚えでどんな現象だったのかを書いておくと、デプロイ途中で何かをcp
するコマンドがあるんだけど、本来は
cp a b c destination/
という風になっていてほしいところを、
cp a b c destination/
と改行が入った状態でコマンドが実行されるようで、b
とかc
みたいなコマンドはありません、というエラーで終了してしまっていた。
調べても全然わからないので別のデプロイツールを探すことに。
Mina
Capistranoが嫌になったのでRuby Toolboxで他のデプロイツールを探したら、Minaってのを見つけました。
The Ruby Toolbox - Deployment Automation https://t.co/qy26fJfXO6
— hiromasa (@xoyip) August 27, 2015
こっちにする https://t.co/kD6Ipm9Frs
— hiromasa (@xoyip) August 27, 2015
今回やりたかったデプロイプロセスはすごく単純で、
- ソース持ってくる
- bundleする
- db:migrateする
- asset:precompileする
- Apacheを再起動する
っていうだけだったので設定はほとんどいらなかった。サーバーの情報やソース管理のURLぐらいかな。
Minaの使い方はREADMEにある通りで、まず、
$ mina init
して設定ファイルを生成し、次にその設定ファイルの一部をこんな風に書き換え、
require 'mina/rbenv' # コメントを外す set :user, 'hiromasa' set :domain, 'vps' # ~/.ssh/configのHostを使うと便利 set :deploy_to, "/home/hiromasa/apps/myappname" set :repository, 'https://user:password@bitbucket.org/hiromasa/myapp.git' task :environment do invoke :'rbenv:load' # コメントを外す end
次にセットアップコマンドを叩く。
$ mina setup
これをやるとティレクトリ等が生成され、database.yml
やsecrets.yml
が用意される。データベースのパスワードなどはここに書けばいいのでソース管理に含める必要はないということになる。
最後にデプロイコマンドを叩く。
$ mina deploy
capistranoに比べてシンプルに書けた気がする。少なくともcp
で変なエラーは起きなかったし。
databaseの移行
Herokuからデータを移行する。
$ heroku pg:backups capture -a myapp $ curl -o latest.dump `heroku pg:backups public-url -a myapp`
これでPostgresqlのdumpが手に入るので、さくらVPSのデータベースにインポートしてあげれば良い。
# ローカル $ scp latest.dump vps:~/ # リモート pg_restore --verbose --clean --no-acl --no-owner -U hiromasa -d mydatabse latest.dump
これで無事動くようになりました。
これで18時間で止まることもなくなったし、日本のサーバーになったのでレスポンスが速くなり快適に使えるようになった。おしまい。

チーム開発実践入門 ~共同作業を円滑に行うツール・メソッド (WEB+DB PRESS plus)
- 作者: 池田尚史,藤倉和明,井上史彰
- 出版社/メーカー: 技術評論社
- 発売日: 2014/04/16
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (11件) を見る