APIフレームワークGrapeをRuby on Railsの中で動かすと遅いぞ

ある仕事でスマフォ用のAPIサーバーを作る事になり、REST-like APIが簡単に作れるフレームワーク grape を調査してみました。grapeの良さは、DSLで簡単にAPIサーバーが書ける点とRackで動く軽いフレームワークなのでRuby on Railsに比べ高いパフォーマンスが期待できる点です。

システム構成

Grapeは Mounting に書かれているようにいくつかの構成で動かせます

今回のシステムでは管理者用のWebアプリは Ruby on Railsで作るので、モデルを共有できるRuby on Railsに組み込み使うのが魅力的です。

評価用コードを作ってみた

準備

  • まずはRailsのプロジェクトを作り、scaffoldでいつものアプリを作成
$ rails new api_test
$ cd apt_test
$ rails g scaffold todo due:date task:string
  • テストデータ作成 db/seed.rb も作成
Todo.delete_all
100.times { |i| Todo.create!(due: Time.now + i.day, task: sprintf("task%02d", i)) }
  • 性能比較のために app/views/todos/index.json.jbuilder を変更
json.array!(@todos) do |todo|
  json.extract! todo, :id, :due, :task, :created_at, :updated_at
end

Grape

grape ページの情報を基に API を作成

  • Gemfile
source 'https://rubygems.org'
  ....
gem 'grape'
  • API のコード
class SimpleApi < Grape::API
  version 'v1'
  format :json

  resource :todos do
    desc "Return all todos."
    get  do
      Todo.all
    end
  end
end
  • config/routes.rb に APIをマウント
Rails.application.routes.draw do
  resources :todos
  mount SimpleApi => '/api'
end
  • config/application.rb にAPIのコードを読み込むように設定
module ApiTest
  class Application < Rails::Application
    ....
    config.paths.add File.join('app', 'api'), glob: File.join('**', '*.rb')
    config.autoload_paths += Dir[Rails.root.join('app', 'api', '*')]
  end
end

これで http://localhost:3000/api/v1/todos をアクセスするとtodosテーブルの全内容がJSONで取得できます

性能が気になる

Ruby on Railsのコードも http://localhost:3000/todos.jsonJSONを返せるます。grapeがどれくらい性能が良いのかを比較してみました。

比較する環境は実際の環境に近くなるように

  • RAILS_ENV は production
  • サーバーは unicorn、worker_processes は 4
  • アプリは EC2 t2.micro で実行
  • ただし、RDBはsqlite3のまま、Nginx等のフロントエンドは無し

ab -c 8 -n 1000 URL で性能を計測

Framework Requests per second
Grape within Rails 33.66
Ruby on Rails 34.49

Grape の性能は Ruby on Rails と同じくらい!? もちろん、テストデータ、abのパラメータにより多少状況は変わりますが・・・

ActiveRecord without Railsを試した

Rackの上で直接動くシンプルな grape の性能がこんなに低いのは納得出来なかったので、ActiveRecord without Rails で試してみました

  • Rackの上で動かす grape.ru を作成
require 'grape'
require 'active_record'
require 'sqlite3'
require_relative 'app/api/simple_api'
require_relative 'app/models/todo'

use ActiveRecord::ConnectionAdapters::ConnectionManagement
ActiveRecord::Base.configurations = YAML.load_file('config/database.yml')
ActiveRecord::Base.establish_connection(:production)

run SimpleApi

この grape.ru を指定し unicorn 起動

Framework Requests per second
Grape 56.65

Ruby on Rails に比べ 1.6倍の性能が出ました!

結論

テスト中のサーバーのメモリー使用量も調べてみました。実メモリ使用量(RES)は Ruby on Railsに比べると半分以下です。

Framework Requests per second VIRT(memory) RES(memory)
Grape within Rails 33.66 345308 91828
Ruby on Rails 34.49 345308 91828
Grape 56.65 253472 38852

結論としては、grape を使って API サーバーを作るなら Rackベースで起動し、 Ruby on Railsとは別に動かした方が良い。

ただし、開発時は Ruby on Railsの中で動かした方が開発しやすいかも知れませんね。

開けましておめでとうございます。本年もEY-Officeをよろしくお願いいたします。

2015年、開けましておめでとうございます。

本年も吉田裕美ならびに、EY-Officeをよろしくお願いいたします。お正月休みに考えた事を少し書いてみました。

f:id:yuum3:20150105103907j:plain

すし処佐治のおせち料理

EY-Officeの歴史を振り返った

2000年に長年勤めたCADのベンチャー企業から独立し EY-Office という会社を作り1人で仕事を始めました。開発や教育の仕事自体は私一人で行っていますが、お金の面を中心に大塚絵理さんに助けてもらっている2人の会社です。

もう独立してから、15年に成ろうとしています。そこで簡便的に5年に区切りまとめてみます。

2000〜2004年

独立し開発を始めたとはいえ、実はお仕事の殆どは一つの会社から受託していました。以前行っていたCADの開発とはまったく違うWeb系の仕事で色々な事を学ばせて頂きました。そして、その会社の売り上げの中心になるサービースのWeb Application Framework を作りました。CADの会社でもCADのベースになる図形データを扱う基本部分を作ってきた経験が生かせ、その会社の社長の経験や発想を混ぜたユニークなフレームワークが出来たと思っています。

また、Perl言語を使って開発していたので Perlのコミュニティーである Shibuya.pm に参加し、色々な方と知り合えたり、他の技術系のコミュニティー(例えば Seasarプロジェクト) などにも参加するようになっていきました。

2005〜2010年

一つの会社から受託していると その会社の経営状況に依存します、またコミニュティーなどを通じて得た新しい技術を試すことも出来なくなります。

そして一つの会社の仕事を行っていると、サラリーマンとそれほど変わらない立場、メンタルになってしまします。そこで、コミニュティーなどを通じて知り合った方などに紹介して頂いた新しい会社とのお付き合いが始まりました。

この時期にEY-Officeにとって大きな事がおきました。一つは、開発でお付き合いのあった会社から「教育」を行ってくれないかという依頼があり、コミニュティーの学んだスタイルを元におそるおそる教育を行ってみました。 長年開発しかしてこなかったので、講師としての能力の低さを痛感しながらも教えるのは面白いなと感じました。

さらに、空前のRuby on Railsブームが起こり、キャッチアップするために Rails勉強会@東京 に参加するようになりました、超出来るプログラマー達が集まる勉強会はとても刺激的でした。そして何回か参加する頃から初心者向けのセッションを行うようになっていきました。これが現在の EY-OfficeのRuby on Rails教育へと繋がって行きました。

2010〜2014年

Ruby on Rails教育 はEY-Officeという会社としての初めてのビジネスだったのかも知れません。しかし営業力もなく、Ruby on Railsブームも開発者だけでの盛り上がりで教育ビジネスでだけで食べて行くことはできず、受託開発も行いながらたまに教育を行うというスタイルが続きました。ただし、2012年頃から経営層にもRuby on Railsが届いたようで、大企業からも教育の注文が来るようになってきました。

しかし教育の仕事を絶えず取るのは難しいです、しばらく仕事絶えてしまう事もありました、そんなあるとき iPhoneMacも持っているのだからiPhone開発でもやってみるか! という感じで勉強でアプリを作ったり、受託でアプリを作ったりしました。 iPhoneの開発情報は当初NDAで保護されていた事もあり開発コミニュティー等が少なかったのですが、ある時期から勉強会が始まり参加するようになりました。 自分が勉強して来た事は教育コンテンツとして教えられると判っていたので、iPhone開発の教育も始めました。ある時期はかなり需要がありましたが、現在はあまり需要がないようです。

仕事が絶えてしまった時にコミニュティーで知り合った方から仕事を頂いたり、たくさんの方のおかげで何とかやっている状況でした。

さて今年はどうしようか

昨年は、このブログ、会社のホームページ 開発の仕事を募集したのですが、ほぼありませんでした。教育の仕事はある程度あるのですが、夏は暇で(Docker, Node.js,Swift,Go..など)たくさんのお勉強をする時間に恵まれてしまいました ^^;

昨年末に、以前お世話になった方から小規模の開発の仕事を頂きました。その方と話をしていた時に、受託はどうしてもお客様に依存してしまうので、やはり自社で何かビジネスをしないとダメなのではと言われました。

また最近はベンチャーがたくさん立ち上がって来ていますが、最初から開発者を抱えて自分たちのビジネスを育てています。以前に比べると技術者の流動化は高まっていて、魅力的なビジネス・経営者であれば優秀なエンジニアをリクルートしやすくなり、フリーの技術者に頼る必要性が下がってきたのかも知れません。 開発会社としてのEY-Officeや開発者としての吉田裕美というのは知名度が低すぎマーケットに届いていないと思います。

そこで、今年はどうするかですが、

  • 教育ビジネスも力を入れて行っていきます。
  • 受託の開発案件も引き続き探します、よろしくお願いいたします。
  • 今のところ、自社サービスやアプリの目処はないですが、今年はあいている時間で思いついた、小さなアプリやサービスをリリースしていきたいと思います。少しずつアイデアを貯めています・・・・
  • 頂いた仕事は、開発も教育も自分の力を出し切りがんばって行きます。

さらに個人的には

  • 英語力の無さを痛感しています。挨拶程度の会話は出来ますが、現在は issueを書いたり質問をしたり出来る能力が不足しています。中学校2年くらいですでに英語を捨てていたの単語力や基本的な文法力がありません。先ずはこの辺をクリア出来るようにしたと思います。
  • 歳をとり体力が落ちています、近くの公園でのジョギングを毎週おこなうように心がけます、昨年も時々行っていたのですが、ついつい行かない時期がありました。

結論

お仕事募集中です !

本気のiOS開発者は読むべき一冊「UIKit徹底解説 iOSユーザーインターフェイスの開発」

入門書や入門講座などを終わり、これから本気でiOSアプリを作るぞ! と思っているいる人は買うべき一冊です。またiOSアプリを一つ二つ作った人も「なるほど!」と思うUIKitの知識が詰まっています。

内容はiOS7用に書かれているので iOS8で導入された機能やSwift言語には対応していませんが、ここに書かれている内容は iOS8でもほとんどが使えます。また SwiftiOSアプリを書く場合もUIKitは同じですから、ほんの少しの脳内コード変換で使えます。

電子書籍も買えるのが嬉しいですね (Kindle以外に PDFも 達人出版会から買えます)

この本の読み方

問題解決

最初から読む必要はありません。テーマー毎にチャプターになっていますので、興味のあるところ、今作っているアプリが思うように動かない時に関連しそうなチャプターを読むと良いと思います。

内容は、かなり細部まで書かれています。 特に自分の作っているアプリのUIが思っているように動作しない時や、他のアプリで実現されている機能がどうやったら実現できるのか判らない時には StackOverflow や Qiita のような回答そのものではなく、iOSの原理や設計思想などの基本部分に付いても学べます。

スキルアップ

ネット上の情報には偏りがあります。また、UIに付いての解説はたくさんの概念図やスクリーン画像、適切なサンプルコードが必要になるので日本語での良質な情報はネット上には少ないと思います。

本書のような本を読むことは、自分の中で欠けている知識の補足になりますし、あらためてiOSの原理や設計思想などの基本部分を学ぶ事で開発力を高める事ができます。

また、分かりにくい Text Kit や UITableView、UICollectionView の高度な使い方も解説されています。

SwiftからEvernote APIを使うのが予想外に面倒だったのでまとめました

SwiftEvernote APIを使うiOSアプリを作ろうとして、なかなか上手く行かなかったので、今回行った手順をまとめておきました。

基本的には Using the Evernote API from Swift に書かれた手順ですが、上手く行かなかったので少し追加しました。

手順

1. Evernote Cloud SDK for iOS の追加

GitHubのEvernote Cloud SDK for iOS を submodule としてプロジェクトに追加します

%  git submodule add https://github.com/evernote/evernote-cloud-sdk-ios.git
Cloning into 'evernote-cloud-sdk-ios'...
...
% git submodule
 804c0ff4221a430fa5e9619ca717503abdad92c8 evernote-cloud-sdk-ios (heads/master)

2. プロジェクトへ追加

の2つをプロジェクトに追加します

f:id:yuum3:20141216112243p:plain

3. 依存ライブラリーの追加

Getting Started with the Evernote Cloud SDK for iOS に書かれているように、以下の2つのフレームワーク・ライブラリーを追加します。

  • MobileCoreServices.framework
  • libxml2.dylib

f:id:yuum3:20141216113057p:plain

4. ブリッジヘッダーファイルを書く

SwiftからObjective-Cで書かれたライブラリーを呼び出すには、ブリッジヘッダーファイルを作る必要があります。ブリッジヘッダーファイルは半自動で出来るように書かれた ドキュメント もありますが、出来なかったので手動でつくりました。

f:id:yuum3:20141216143646p:plain

  • EvernoteSample-Bridging-Header.h の内容
#import <ENSDK/ENSDK.h>
  • Build Settings

f:id:yuum3:20141216144030p:plain

EvernoteSample/EvernoteSample-Bridging-Header.h

5. Header Search Path

ここでコンパイルしてもエラーが出ます。Evernote Cloud SDK for iOS や libxml2 のヘッダーファイルが見つからないからです。設定しましょう

f:id:yuum3:20141216144543p:plain

${PROJECT_DIR}/evernote-cloud-sdk-ios/evernote-sdk-ios

/usr/include/libxml2

6. Prefix Header の設定

ここまでで Using the Evernote API from Swift に書かれた設定は全て出来たはずですが、以下のような意味不明なエラーが出て悩みました・・・

f:id:yuum3:20141216145210p:plain

そしてGoogle先生にたずねながら理解しました。Evernote Cloud SDK for iOS内には独自のPrefix Header evernote-sdk-ios-Prefix.pch が在るのですが、これが参照されてないようです

f:id:yuum3:20141216145224p:plain

そこで Prefix Header を設定。 これでコンパイルエラーが無くなりました ^^)/

f:id:yuum3:20141216145732p:plain

${PROJECT_DIR}/evernote-cloud-sdk-ios/evernote-sdk-ios/evernote-sdk-ios-Prefix.pch

サンプルコード

この記事を書くために Evernote Cloud SDK for iOSを使いノートを作成する簡単なテストコードを作りました、コードは GitHub にあります。

import UIKit

class ViewController: UIViewController {
    let CONSUMER_KEY    = "YOUR CONSUMER_KEY"
    let CONSUMER_SECRET = "YOUR CONSUMER_SECRET"

    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        postTestNote()
    }
    
    private func postTestNote() {
        ENSession.setSharedSessionConsumerKey(CONSUMER_KEY, consumerSecret: CONSUMER_SECRET,
            optionalHost: ENSessionHostSandbox)
        
        var session = ENSession.sharedSession()
        if session.isAuthenticated {
            var note = ENNote()
            note.title = "Test"
            note.content = ENNoteContent(string: "test test test ...")
            session.uploadNote(note, notebook: nil, completion: { noteRef, error in
                if error == nil {
                    println("OK")
                } else {
                    println("Upload note error: \(error)")
                }
            })
        } else {
            session.authenticateWithViewController(self, preferRegistration: false, completion: { error in
                if error == nil {
                    self.postTestNote()
                } else {
                    println("Authentication error: \(error)")
                }
            })
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}
  • CONSUMER_KEY/CONSUMER_SECRET は https://dev.evernote.com/intl/jp/doc/ から取得して下さい
  • 作成されるのは sandbox.evernote.com の方です、ノートブックはデフォルトが使われます
  • 画面が表示された瞬間(viewDidAppear)にノートをEvernoteに作ります
  • 最初に起動した際に認証画面が表示されます

UIVewのanimateWithDuration〜メソッドを他のUI更新と一緒に実行してはいけない!

昨晩から、約4時間をこの問題の解決に費やしてしまいまいました 。。。。他の人が同じ間違いしないように記録しておきました。

あるアプリに下のような動きをする、簡単なアニメーションを付けました(この画像、コードは説明用サンプルです)。

f:id:yuum3:20141128153650g:plain

失敗のはじまり

コードは以下のように書きました。

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UILabel *scrollLabel;
@property (weak, nonatomic) IBOutlet UILabel *statusLabel;
- (IBAction)touchStartButton:(id)sender;
@end

@implementation ViewController

- (IBAction)touchStartButton:(id)sender {
    _statusLabel.text = @"scrolling...";
    [UIView animateWithDuration:2.0 animations:^{
        _scrollLabel.center = CGPointMake(_scrollLabel.frame.size.width * -0.5, _scrollLabel.center.y);
    }];
}

このコードは、 statusLabel に scrolling... と表示してから、scrollLabel(黄色いバックグラウンドのラベル)を 2秒かけて、左端に追い出します。

しかし、動かすと下のように動作します ^^; scrollLabelのY座標は、画面の中央にあるはずなのに、なぜかアニメーション開始時右端からはじまります (>_<)

f:id:yuum3:20141128153636g:plain

実際のアプリは、こんなにシンプルではないので、いろいろと調べてみましたが・・・・・。 また AutoLayoutだとアニメーションが思ったように動作しないなど記事を見つけ、また、あーだーこーだー・・・。 ちなみに上のサンプルは AutoLayoutは使っていません。

解決編

そこで、シンプルなサンプルを作り実験してみました。すると正しく動作するコードが判りました!! なんと、 statusLabel に @"scrolling..." を代入するのを止めれば良いのです。

あああ! やっと判りました。それをタイトル「UIVewのanimateWithDuration〜メソッドを他のUI更新と一緒に実行してはいけない!」にしました。 iOSでのほとんどの画面操作API等は、呼び出した(statusLabelへの代入も同じく)瞬間に実行されるのではなく、イベント待ちに戻った時に実行されます。上のコードではアニメーションとstatusLabelの表示変更が同事(?)に行われアニメーションが正しくない動作になってしまうのです。

そこで、以下のコードのようにstatusLabelへ代入を行った後でアニメーションを始めれば正しい動作になるのです。(^○^)

#import "ViewController.h"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UILabel *scrollLabel;
@property (weak, nonatomic) IBOutlet UILabel *statusLabel;
- (IBAction)touchStartButton:(id)sender;
@end

@implementation ViewController

- (IBAction)touchStartButton:(id)sender {
    _statusLabel.text = @"scrolling...";
    [self performSelector:@selector(scrolling) withObject:nil afterDelay:0.1];
}

- (void)scrolling {
    [UIView animateWithDuration:2.0 animations:^{
        _scrollLabel.center = CGPointMake(_scrollLabel.frame.size.width * -0.5, _scrollLabel.center.y);
    }];
}

@end

LoopBack (Open SourceのBaaS)を使ってみよう! その1. PostgreSQL接続とTwitter認証

あるiOSアプリを作ろうとしています、このアプリはバックエンドのサーバーと情報をやり取りします。バックエンドのサーバーはRuby on Railsで作ってもよいのですが、なるべく早くプロトタイプを動かしたいので、今回は既存のBaaS(Backend as a Service)を使ってみる事にしました。

LoopBack Architecture!

1. なぜ LoopBack を使う事にしたのか

現在BaaSのサービス、Open Sourceのソフトはたくさんあります。ネット上でいろいろと調べてみると BaaS にもサービスよりのものとプラットフォームよりのものがあります(この分類は、私がそう思っているだけかもしれません)。

サービスより のもとしては、実際に良く使われている Parse があげられます。Parseはプッシュ通知やアプリのデータ同期・共有などを複数のプラットフォーム(iOS,Android,PC...)に提供するサービスです。

プラットフォームより のものとしては、Loopbackや以前は話題になったdeploydなどがあります。これらはスマフォとやり取りするAPIサーバーを構築するためのフレームワーククラウドです。 LoopbackはOpen Sourceのソフトですが、それをクラウドで提供するStrongLoopのような会社もあります。

BaaSは現在も進化・競争している世界で、どのサービス・ソフトが良いのかは 簡単には決められない世界のようです。詳しくはBaaSはまだ戦国時代だったのか、まとめ。(執筆中)が参考になります。

今回、Loopbackを使う事にした理由は

  • プラットフォームよりで、今回作るアプリに適切
  • Open Sourceなので、突然のサービス停止にも泣かない
  • ドキュメントもそれなりにある
  • いろいろとサンプルコードがある
  • Node.jsベース。Node.jsはまだまだ初心者ですが Ruby/Railsの世界感にも近い
  • サーバーを自前で準備する必要があるが、このへんは慣れいてる

2. LoopBack入門

a. 前提条件

LoopBackを使うには、Node.js を使って簡単なWebアプリを作れる知識・経験が必要だと思います。

  • JavaScript
  • Node.js
  • npm コマンド
  • 英語ドキュメントが読める (LoopBackの日本語の情報はほぼありません)

b. 入門

  1. node.jsのインストール (v0.10.xを使って下さい。v0.11.xでは動きません)
  2. LoopBackのGetting startedページを試す
    • Ruby on Railsの scaffold のようなものです
    • Modelを定義すると、そのモデルのCRUD操作が出来るREST APIサーバーが出来ます
    • プロジェクトの構成、設定ファイルの役割等を知って下さい
  3. ドキュメントを読みましょう(先にExamplesを試しても良いですが、たぶん読まないと詰まります)
  4. LoopBackのExamplesの興味があるものを試す
    • Examplesのリンク先はGitHubです
    • 詳しい手順が書かれています。たいてい git clone して設定ファイル等を変更し実行する流れです
    • 手順通りにやっても動かない事もままあります。がんばって対応しましょう、とても勉強になります ^^;
    • コードはJavaScriptで書かれています、問題になっているコードを読んでみましょう

3. LoopBackをPostgreSQLにつなぐ

概要

LoopBackはいろいろなDBと接続出来るようになっていますが、大きく2つのタイプがあります

  • MongoDBのようなダイナミックDB
    • このタイプのDBを使う場合はModelにはプロパティー(カラム)の定義が不要です
    • Examplesで使われている Memory もこのタイプです
    • Node.js的にはこのタイプのDBを使うのがお手軽でよいのかもしれません
    • RDBを使う場合も、まず Memory 等で動作を確認してからRDBに置き換えると良いと思います
  • RDB
  • 先ずはGitHubloopback-example-databaseをcloneして動かしてみるのが良いと思います
  • ドキュメントはData sources and connectorsPostgreSQLをつかうならPostgreSQL connector

設定ファイル

LoopBackではDBと接続するための設定ファイルがいくつかあります

  • server/datasources.json : 接続するDBの定義ファイル。
    • 複数のDBを使う事が出来ます
    • Memory DBは最初から定義されています
    • PostgreSQLの定義ファイルにはDatabase名、login、passwordやサーバーなどの情報を書きます、他のソフトでもよくあるものだと思います。
{
  "db": {
    "name": "db",
    "connector": "memory"
  },
  "pgDB": {
    "name": "pgDB",
    "connector": "postgresql",
    "port": 5432,
    "debug": true,
    "database": "node_test",
    "username": "node_test",
    "password": "node_test"
  }
}
  • server/model-config.json: Modelの一覧と、Modelが使うDBなどの定義。
    • 最初の _meta の sources は Modelファイルのある場所のリスト
{
  "_meta": {
    "sources": [
      "../common/models",
      "./models",
      "./node_modules/loopback-component-passport/lib/models"
    ]
  },
  "user": {
    "dataSource": "pgDB",
    "public": true
  },
    ....
  "Role": {
    "dataSource": "db",
    "public": false
  }
}
  • common/models/Model名.json : Modelの定義
    • 対応するRDBのテーブル名、カラム名、型や関連などを定義します
    • optionsを指定する事で、細かいテーブル・カラムの設定が書けます
    • 定義の意味はData sources and connectorsと下位のページに書かれていますが、全てが網羅された情報は無いようです(?)
    • デフォルトでは、Model名、プロパティー名がテーブル名、カラム名にそのまま使われます。対応を変えたい場合はoptionsで指定する必要があります
    • テーブルにはプライマリーキーが必要です、idInjectionをtrueにすればRailsのように整数型のidカラムが自動生成されます
    • 関連情報relationsにはRails同様に hasMany, belongsTo が定義出来ます
{
  "plural": "users",
  "base": "User",
  "options": { "postgresql": { "table": "users" } },
  "idInjection": true,
  "properties": {
    "username": {
      "type": "String",
      "required": true
    },
    "password": {
      "type": "String",
      "required": true
    }
  },
  "relations": {
    "accessTokens": {
      "type": "hasMany",
      "model": "accessToken",
      "foreignKey": "userId"
    }
  },
  "validations": [],
  "acls": [],
  "methods": []
}
  • 他の例
    • 特定のカラムをプライマリーキーにしたい場合は、idInjectionをfalseにし、プロパティーにid属性を指定をします。
{
  "name": "accessToken",
  "plural": "accessTokens",
  "base": "AccessToken",
  "options": { "postgresql": { "table": "access_tokens" } },
  "idInjection": false,
  "properties": {
    "id": {
      "type": "String",
      "id": 1,
      "required": false
    },
    "ttl": {
      "type": "Number",
      "required": false
    },
    "userId": {
      "type": "Number",
      "postgresql": { "columnName": "user_id" },
      "required": false
    },
    "created": {
      "type": "Date",
      "required": false
    }
  },
  "validations": [],
  "relations": {},
  "acls": [],
  "methods": []
}
  • server/create-test-data.js : テーブルの作成とテストデータの作成
    • このファイルは自動生成されないので、Exampleからコピーして作る必要があります。
var server = require('./server');
var dataSource = server.dataSources.accountDB;
var Account = server.models.account;
var accounts = [
    { email: 'foo@bar.com',
      created: new Date(),
      modified: new Date()
    }, {
      email: 'bar@bar.com',
      created: new Date(),
      modified: new Date()
    } ];

var count = accounts.length;
dataSource.automigrate('account', function(er) {
  if (er) throw er;
  accounts.forEach(function(account) {
    Account.create(account, function(er, result) {
      if (er) return;
      console.log('Record created:', result);
      count--;
      if(count === 0) {
        console.log('done');
        dataSource.disconnect();
      }
    });
  });
});

4. LoopBackでTwitter/Facebookの認証を使う

概要

LoopBackにはThird-party loginとい機能があり、これを使うと簡単にTwitter/Facebookの認証を使う事ができます。

設定ファイル

設定ファイルは providers.json で loopback-example-passportには providers.json.template が用意されているのでコピーして使ってください。

{
  "local": {
    "provider": "local",
    "module": "passport-local",
    "usernameField": "username",
   ...
  "twitter-login": {
      "provider": "twitter",
      "authScheme": "oauth",
      "module": "passport-twitter",
      "callbackURL": "http://localhost:3000/auth/twitter/callback",
      "authPath": "/auth/twitter",
      "callbackPath": "/auth/twitter/callback",
      "successRedirect": "/auth/account",
      "consumerKey": "ここにconsumerKeyを指定",
      "consumerSecret": "ここにconsumerSecretを指定"
  },
    ....
}

5. LoopBackでPostgreSQL接続とTwitter認証

PostgreSQLに接続し、Twitter認証が行えるようにしてみました。 GitHubloopback-example-passportをPostgreSQL対応した例 を置きました、これを参考にして下さい。

  • PostgreSQLのテーブル定義は、後々の事を考えRuby on Railsのルールに合わせました
  • providers.jsonTwitterの consumerKey, consumerSecretを入手し作って下さい
  • server/create-test-data.js を実行するとテーブルが作成されます
  • loopback-example-passportは Memoryを使っているので、user モデルにカラム定義がありませんが server/datasources.json に file属性を指定するとDBをファイルにJSONで保存してくれるのでそれを見てカラム定義は作りました
  • user モデル以外の認証に必要なモデルの定義はThird-party+loginに書かれています

ドキュメントには書かれてない部分があったり、callbackの中で起こるエラーはtracebackが在っても役に立たず苦労しました ^^);

Jekyllを1.5.1から2.3.0にアップデートした

私は会社のホームページや教育で使うテキストはJekyllを使って作っています。

最近ずっとアップデートしてなかったので、久しぶりにアップデートしてみました。使っていたのは 1.5.1 で現在の最新は 2.3.0 とメジャー・バージョンアップになるので少し不安でしたが、とくに問題なくアップデートできました。

Jekyll

アップデート手順

通常のRubyプログラムのアップデートと同じです。アップデートでJekillの生成するHTMLがおかしくなってないか確認するために現在の変換結果 _site/以下を保存しておき、アップデート後diffを見られるようにしたくらいです。

% mv _site _site.0     # 現バージョンの変換結果を保存
% mkdir _site
% bundle update      # Jekyllと関連するgemはbundleで管理しています (中身は jekyllとRedCloth)
Fetching gem metadata from https://rubygems.org/........
Resolving dependencies...
Using RedCloth 4.2.9
Using blankslate 2.1.2.4
...
Installing redcarpet 3.1.2 (was 2.3.0)
Using safe_yaml 1.0.3 (was 1.0.1)
Using parslet 1.5.0
Using toml 0.1.1
Installing jekyll 2.3.0 (was 1.5.1)
Using bundler 1.6.2
Your bundle is updated!
% rbenv rehash
% jekyll -v
jekyll 2.3.0
% jekyll server --watch --port 4000  # Jekyllを起動すると幾つかのワーニングが
Configuration file: /Users/yy/Documents/jekyll-ey-office/_config.yml
       Deprecation: The 'pygments' configuration option has been renamed to 'highlighter'. Please update your config file accordingly. The allowed values are 'rouge', 'pygments' or null.
            Source: /Users/yy/Documents/jekyll-ey-office
       Destination: /Users/yy/Documents/jekyll-ey-office/_site
      Generating... 
     Build Warning: Layout 'nil' requested in atom.xml does not exist.
                    done.
 Auto-regeneration: enabled for '/Users/yy/Documents/jekyll-ey-office'
Configuration file: /Users/yy/Documents/jekyll-ey-office/_config.yml
       Deprecation: The 'pygments' configuration option has been renamed to 'highlighter'. Please update your config file accordingly. The allowed values are 'rouge', 'pygments' or null.
    Server address: http://0.0.0.0:4000/
  Server running... press ctrl-c to stop.
% 

ワーニングに対応

  • _config.yml これはワーニングメッセージにある通り修正
-pygments: false
+highlighter: :pygments
-layout: nil
+layout: null

レイアウト無しがの指定が nil から null に変更されたのですね (ナゼ^^;)

確認

RSSの作成日付が変わったのみで、生成されるHTMLはまったく同じでした!

% jekyll server --watch --port 4000
...
^c
% diff -r _site.0 _site
diff -r _site.0/atom.xml _site/atom.xml
7c7
<  <updated>2014-09-08T16:19:29+09:00</updated>
---
>  <updated>2014-09-08T17:32:18+09:00</updated>

独自の_plugin(マクロ)も使っていますが、問題ありませんでした。