MIKAZUKI 開発者ブログ

MIKAZUKI で開発を進める上で見つけた気づきやノウハウをお伝えするテックブログです。

Rails5のAPImodeでアプリケーションを作成するところまでやってみた話

やったこと

開発しているiosアプリのAPIを作りたく、せっかくなら18日に出たRails5のベータでも使ってみようと思い、環境を構築した。

rbenvのアップデート

rbenvを使っているのだが、rails5はruby2.2.2以上が必要だったのでアップデートをする必要があった。

# ruby-buildをアップデート
$ brew upgrade ruby-build

$ rbenv install 2.2.3

# 今回作成するアプリケーションにのみ2.2.3を使用する
$ rbenv local 2.2.3

# 設定結果を確認
$ rbenv versions

rails5のインストール

本当はrailsアプリケーション内のGemfileで管理したかったのだが、

$ rails new my_api --api

を試してみたかったので普通に

$ gem install rails --pre

を叩いた

APImodeでのアプリケーション作成

http://edgeguides.rubyonrails.org/api_app.html を参考に

$ rails new my_api --api

と打ってみる。

generateされたアプリケーションのapplication.rbを見てみると

config.api_only = true

application_controller.rb

class ApplicationController < ActionController::API
end

APIモードでのrailsアプリケーションが生成されていた。

起動させてみる

なにも考えずに

$ bundle exec rails server

=> Booting Puma
=> Rails 5.0.0.beta1 application starting in development on http://localhost:3000
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
I, [2015-12-26T13:58:52.252332 #10939]  INFO -- : Celluloid 0.17.2 is running in BACKPORTED mode. [ http://git.io/vJf3J ]
Puma 2.15.3 starting...
* Min threads: 0, max threads: 16
* Environment: development
* Listening on tcp://localhost:3000

WeblickではなくPumaが立ち上がった。(rails5がpumaを採用しているのか、apiモードのみなのかはまだ調べられていない。というか4.1系をずっと使っていたのでどこかのタイミングで変わったのか、、?)

とりあえずアクセスするといつものページが表示されたので、ひとまず起動はうまくいったっぽい。

APIっぽい仕事をさせてみる

class PostsController < ApplicationController

  def index
    @posts = Post.all
    render json: @posts
  end

  def show
    @post = Post.find_by(params[:id])
    render json: @post
  end
end

上記のような適当なコントローラを作成して(省略しますがモデルやルーティングも) localhost:3000/posts/1を叩いたら {"id":1,"name":"hogehoge","contents":"fugafuga","created_at":"2015-12-26T05:46:08.955Z","updated_at":"2015-12-26T05:46:08.955Z"} と結果が返ってきてくれた。

なにが嬉しいのか

正直上のようにjsonで返すことを明記すれば今までのrailsでも同じような挙動になっていたはず。(というかそのようにAPIサーバをrailsで構築していたものを多いと思う。もちろんGrapeとか使っているのも多いけど)

おそらく僕がリファレンスなどを全然読めてないので、もっとAPIに特化したうまい書き方があるはず。

また、今回のAPIモードの最大のポイントはAPIサーバとして必要最低限のミドルウェアで動かせる、というところのような気がしているのでもっと大きなデータで検証とかしてみたいと思った。

そんなわけでさらっと使ってみただけだと、なにが嬉しいのかあまり実感できなかったが、ミドルウェア周りの話とかAPサーバの話とか、単に自分に知識がないから実感できていないだけの気がしたので勉強します。。。

Realmを用いて合コンで活躍するアプリを開発した

今日の話

Realm使いやすい!おすすめ!ってはなしと合コンでは是非我々のアプリ使ってって話

Realmとは

CoreDataやSQLiteに変わる次世代Mobileデータベースです。

Realm is a mobile database: a replacement for SQLite & Core Data

メリット

  • Androidに対応していること→i/A際を意識せずDB設計できること
  • SQLiteより速いらしい
  • PrimaryKeyがある。
  • NSManagedObjectContextなしでオブジェクトが生成できる。
  • RLMResultsが良い
    • NSPredicate、NSCompoundPredicateを利用してクエリを作れる
  • RealmBrowserでDBをGUIで確認できる

デメリット

  • オートインクリメントがない
  • FetchRequestが弱い→limitとかない

導入方法

Podfile内に下記を追記 pod install

pod 'RealmSwift'

#Objective-Cなら
pod 'Realm'

使い方

モデル定義

class Person: Object {
   // オプショナル使える
   dynamic var name: String? = nil
   dynamic var id = 0

  //数値をオプショナルで扱う場合はRealmOptionalでラップする
  let age = RealmOptional<Int>()

  //プライマリーキーの設定も可能
  override static func primaryKey() -> String? {
    return "id"
  }
}

CREATE

//Realmオブジェクト作って、write使って書き込む
let realm = try! Realm()
try! realm.write() {
    //オブジェクト生成
    var person = realm.create(Person.self, value: ["Jane", 27])
    //プロパティの設定
    person.age.value = 28
}

READ

let realm = try! Realm()
// 文字列で検索条件を指定します
var tanDogs = realm.objects(Dog).filter("color = 'tan' AND name BEGINSWITH 'B'")
//Result型で返ってくるので、ここからまたフィルタリングできる

let predicate = NSPredicate(format: "name CONTAINS %@", "C")
let tanDogs2 = tanDogs.objects(Dog).filter(predicate)

UPDATE

// 1.トランザクションを開始して、オブジェクトを更新する
try! realm.write {
  author.name = "Thomas Pynchon"
}


// 2.プライマリーキー設定している時
// 以前に保存したものと同じプライマリキーを持つBookオブジェクトを作成する
let cheeseBook = Book()
cheeseBook.title = "Cheese recipes"
cheeseBook.price = 9000
cheeseBook.id = 1

// id = 1のBookオブジェクトの値を更新する
// ここでid = 1のBookオブジェクトがRealmに保存されていない場合は、新しいBookオブジェクトが追加されます。
try! realm.write {
  realm.add(cheeseBook, update: true)
}

→プライマリーキーを設定したが、なぜかエラーが出てアップデートできなかった。 そのため、1案を採用

DELETE

// トランザクションを開始してオブジェクトを削除します
try! realm.write {
  realm.delete(cheeseBook)
}

// Realmに保存されているすべてのオブジェクトを削除します。
try! realm.write {
  realm.deleteAll()
}

Realmまとめ

  • NSManagedObjectContextとか使わないで、CRUDできるのでCoreDataなどに比べて初期導入コストが低い
  • i/A差異が生まれないので、DB定義書を一つで管理できる→保守運用を考えるとかなりありがたい

フィーリングマッチについて

合コンをした際、「あの子は誰が好きなんだろー?知りたいなー」とか必ず思うと思います。 フィーリングマッチはその欲望を叶えます。

フィーリングマッチ

フィーリングマッチ

  • Ishibe Tatsuya
  • ゲーム
  • 無料

使い方

f:id:mikazuki-ttp:20151109134249j:plain

  1. 合コンの参加者を登録します。

f:id:mikazuki-ttp:20151109134259j:plain

2.意中の相手を選びます。

f:id:mikazuki-ttp:20151109134329j:plain

3.結果を見ます

f:id:mikazuki-ttp:20151109134338j:plain f:id:mikazuki-ttp:20151109134345j:plain

マッチング相手は完全に非公開

誰と誰がマッチングしたかは非公開です。
何組マッチングしたかだけ知ることができます。
そこからはお酒を飲みながら、探りあいましょう



いかがでしょうか?
操作も簡単、プライバシーも守ります。
飲み会が盛り上がること間違いなし!!!

CarrirWaveでgoogle cloud strageにファイルアップロードする

railsで画像ファイルをアップロードするときに CarrirWave を使うことはよくあると思うのだけれど、今回そのアップロード先に使ってみたかったgoogle clowd strageを選択した。

AWSのs3についての記事はたくさんあるものの、google clowd strageについての日本語の記事があまりなく、英語が拙い自分にとってはつらかったのでメモ

基本的に参考した記事はこれ http://www.codediode.io/lessons/8223-upload-files-to-google-cloud-storage-with-carrierwave

上の通りにやっていけば基本的に問題ないはずなのだが、なにせ英語、、、

まずはgemを入れる

gem 'carrierwave'
gem 'mini_magick'
gem 'fog'

carriewave はご存知画像アップロードのためのgem、 mini_magick は画像のリサイズなどを行なってくれる。fog というgemはクラウドサービス向けのgemでcarriewaveと組み合わせるとアップロードの向き先を AWSGoogle Compute Engine などに出来たりする。

carriewaveリポジトリには fog-google というgemを使うよう書いてあるのだが、fogでも普通に動いた。 https://github.com/carrierwaveuploader/carrierwave#user-content-using-google-storage-for-developers

googleAPIキーを設定する

development:
google_storage_access_key_id: "HOGEHOGE-ID"
google_storage_secret_access_key: "HOGEHOGE-SECRET"

ここのkeyとidがいったいどこのなんの値を入れればよいのか、全然わからなかった。

いろいろいじって見たところ、 スクリーンショット 2015-09-15 9.03.09.png

の「設定」から

スクリーンショット 2015-09-15 9.05.04.png

「相互運用性」のタブをクリックし、その中で相互運用アクセスを許可するとアクセスキーと非公開というものが発行される。(キャプチャは相互運用アクセスの設定済みのもの)

このアクセスキーがidで非公開がsecretとなる。(まあsecretは非公開なのだが、わかりにくい、、、)

ただ僕の場合はsecret.ymlにキーをベタで書くのが嫌だったので Railsで環境変数をライトに使う - MIKAZUKI 開発者ブログ

のように環境変数を使うようにした。

development:
google_storage_access_key_id: ENV["GOOGLE_STORAGE_ACCESS_KEY_ID"]
google_storage_secret_access_key: ENV["GOOGLE_STORAGE_SECRET_ACCESS_KEY"]
#gemが必要
GOOGLE_STORAGE_ACCESS_KEY_ID = "hogehoge_id"  #相互運用性のアクセスキー
GOOGLE_STORAGE_SECRET_ACCESS_KEY = "hogehoge_secret" #相互運用性の非公開

あとは http://www.codediode.io/lessons/8223-upload-files-to-google-cloud-storage-with-carrierwave の通り進めていけばオーケー

model と uploader を作成する

$ rails g model Image name:string file:string

$ rails g uploader Image

class Image < ActiveRecord::Base
  mount_uploader :file, ImageUploader
end

strageをfogに設定

class ImageUploader < CarrierWave::Uploader::Base
  storage :fog
end

設定ファイルの記述

CarrierWave.configure do |config|
config.fog_credentials = {

    :provider                         => 'Google',
    :google_storage_access_key_id     => Rails.application.secrets.google_storage_access_key_id,
    :google_storage_secret_access_key => Rails.application.secrets.google_storage_secret_access_key

    }

    config.fog_directory = 'hogehoge-bucket' #GCEのbucketの名前
end

これで設定は完了。

僕の場合はAPIで使いたかったのでviewは用意していなかったが、上で紹介した参考サイトにviewのサンプルもあるので画面から登録する場合はそちらを参考にして欲しい。

ちかれた

CentOs golang環境構築

必要そうなものをインストール

$ sudo yum install curl git make bison gcc glibc-devel

golangのバージョン管理ツールであGVMをインストールする

$ bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)

今回はgolang1.4.2をインストール

$ gvm install go1.4.2

失敗する

##### Building Go bootstrap tool.
cmd/dist
ERROR: Cannot find /home/mikazuki_ttp/go1.4/bin/go.
Set $GOROOT_BOOTSTRAP to a working Go tree >= Go 1.4.
./make.bash: line 121: /home/mikazuki_ttp/go1.4/bin/go: No such file or directory

さあどうしたものか

いろいろ調べた結果 https://github.com/moovweb/gvm/issues/124 gitのバージョンを上げて解決している例がちらほら

そういえば yum updateしないで 思考停止して sudo yum install git してるな、、ということで

$ sudo yum update

そして

$ yum list | grep git
fprintd.x86_64                            0.1-22.git04fd09cfa.el6       @base   
fprintd-pam.x86_64                        0.1-22.git04fd09cfa.el6       @base   
git.x86_64                                1.7.1-3.el6_4.1               @base  
...

あれ、、、yumでは2.x系のgitをインストール出来ないのか、、、

なので http://qiita.com/sirone/items/2e233ab9697a030f1335 の記事を参考にgitを直接入れる

$ sudo yum remove git
$ yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel perl-ExtUtils-MakeMaker
$ wget https://www.kernel.org/pub/software/scm/git/git-2.2.0.tar.gz
$ tar -zxf git-2.2.0.tar.gz
$ cd git-2.2.0
$ make prefix=/usr/local all
$ make prefix=/usr/local install

でうまくいくはずが

install -d -m 755 '/usr/local/bin'
install -d -m 755 '/usr/local/libexec/git-core'
install: cannot change permissions of `/usr/local/libexec/git-core': No such file or directory
make: *** [install] Error 1

パーミッションを変えて再チャレンジ

& git --version
=> git version 2.2.2

でけた

リベンジ!

gvm install go1.4.2
gvm use go1.4.2
go version
=> go version go1.4.2 linux/amd64

golangが無事入りました〜!

apache起動時にPermission deniedで怒られる

いきなりapacheが動かなくなり、原因が意外なところにあったのでメモ

いきなり運用していたサーバが応答しなくなったので、とりあえず再起動でもするか、とsudo service httpd restartを実行。

すると

httpd: Syntax error on line 1 of /etc/httpd/conf/httpd.conf: Cannot load /home/mikazuki_ttp_gmail_com/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/passenger-5.0.13/buildout/apache2/mod_passenger.so into server: /home/mikazuki_ttp_gmail_com/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/passenger-5.0.13/buildout/apache2/mod_passenger.so: cannot open

shared object file: Permission denied

というエラーとともに失敗してしまった。

Permission なんていじってないしなぁと思いつつ権限を確認してみると、問題なく設定されていた。 (念のため sudo chmod 777 /etc/httpd/conf/httpd.conf: Cannot load /home/mikazuki_ttp_gmail_com/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/passenger-5.0.13/buildout/apache2/mod_passenger.so とかしてみるけど案の定効果なし)

なんかこんな事最初にインフラを構築した時に遭遇した気がしたので自分の昔書いたメモを見てると、どうやらSElinuxによる影響が怪しそう

sudo setenforce 0 

SElinuxを無効化してやると無事動くようになった!

GCPGoogle Clowd Platform)の無料期間が終わったので、有料版にアップデートしたのだが、その際に設定もリセットされてしまったのだろうか。。。

javaのDate型でrubyのDateTimeを受け取る

ネイティブはjava(android)、バックエンドはrubyrails)で書かれているアプリケーションのandroid側のコードを触った時の出来事。普段はサーバサイドしか書いていないのでしょーもないことでハマってしまったのでメモ

railsAPIが提供してネイティブ側でそれをごにょごにょしているのだが、railsのモデルが作るcreated_atのフォーマットがjavaのDateだとうまく受け取れなかった。

created_atのフォーマットはこんな感じ

{ "created_at": "2013-07-16T22:52:36Z" }

この辺を見てみると http://jp.androids.help/q2228

Gsonを生成するときに上記のフォーマットを指定してあげればいいらしい

Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss") // こいつを追加した
.create();

これで動くようになりました!

ネイティブも書けるようになりたいです、、、

エミュレータのみでandroid wearの開発環境をつくる

wearを使ったandroidアプリのコードを触る機会があったのだが、自分が実機を持っていなかったので、確認できる環境をエミュレータonlyで構築した。

基本的にはこのへんのリンクのとおりにやればうまくいくはずなんだけど1点はまったところがあったので備忘録的に記録しておく

参考にしたブログ http://lastshooting.blogspot.jp/2014/08/android-wear.html

android wearがエミュレータandroidに入らない

エミュレータのandoridにgoogle playを入れてそこからwearのアプリをインストールしたものの、お使いの端末はこのバージョンに対応していませんと表示されてしまいandroid4.4.4ではインストールできなかった。

5.0.0ならいけるだろ、と思いエミュレータのバージョンを上げてみたが、相変わらずお使いの端末はこのバージョンに対応していませんの表示のままだったので、バージョンの問題ではないような気がして、apkファイルを直接入れた。

ちょうど同じような現象に遭遇されている方がいたので http://qiita.com/mapyo/items/f617be64d3e3f2cee352

の通りにやったのだがgoogle側が対応しているのか、 http://apps.evozi.com/apk-downloader/android wearのURLやIDを入れてもwe have run out of device to fetch your apkと出てしまいダウンロード出来なかった。

なので http://www.apkmirror.com/ からandroid wearを検索してバージョンを選んで(一番新しいやつを選んだら4.4.4には入らなかった)ダウンロード。

そのzipをGenymotion上にドラッグ&ドロップでインストール。

無事android wearがエミュレータのandroid4.4.4に入った。