genonymous

GenestreamのTechブログ

Rails4.2のActive Jobを使って非同期に処理を実行したりメールを送信してみる

こんにちは徳山です。今回はRails4.2の新機能のActive Jobを軽く使ってみたので共有します。

Active Jobとは

  • Rails 4.2から導入されたキューイングの為の仕組み
  • 実際のキューイングはDelayed Job, Resque, Sidekiqなどを使い各キューイングシステムとのアダプターになる
  • バックグラウンドで使うキューイングシステムが何であれ同じように書け、移行コストも下がる
  • Action Mailerも内部で使うようになった
  • ビルドインアダプタは9つ 参考 : Active Job adapters

試しに与えれたメッセージをログに出力するだけのタスクを色々な方法で実行してみます。

今までのDelayed Jobを使った書き方

必要なGemのインストールする

gem "delayed_job"
gem "delayed_job_active_record"

Delayed Jobのキュー保存用のテーブルを作成します。

rails generate delayed_job:active_record
rake db:migrate

Delayed Job workerの起動

rake jobs:work

非同期で実行したいタスクを作成する

class Task
  def exec message
      Rails.logger.info(message)
  end
end

タスクを実行する

Task.new.exec '普通に実行'
Task.new.delay.exec 'Active Jobを使わずに非同期で実行'
Task.new.delay(run_at: 30.seconds.from_now).exec '30秒後にActive Jobを使わずに非同期で実行'

Active Jobを使って書いてみる

Rails 4.2.0をインストールする

gem 'rails', '4.2.0'

application.rbにAdapterの設定を追加する

config.active_job.queue_adapter = :delayed_job

Jobを作成

rails generate job Sample

これで app/jobs/sample_job.rb が生成されます。 受け取ったメッセージをそのままタスクに渡す処理を書きます。

class SampleJob < ActiveJob::Base
  queue_as :default

  def perform(message)
    Task.new.exec(message)
  end
end

Jobの呼び出し

SampleJob.perform_later 'Active Jobを使って非同期で実行'
SampleJob.set(wait: 30.second).perform_later 'Active Jobを使って30秒後に非同期で実行'

Action Mailerを使ったメール送信

  • deliverメソッドはdeplicatedになった(deliver_nowのプレフィックス)
  • deliver_nowを使う
  • deliver_laterは内部でActive Jobを使っているので非同期になる

参考 : ActionMailer::MessageDelivery

MyMailer.confirm(@user).deliver_now
MyMailer.confirm(@user).deliver_later
MyMailer.confirm(@user).deliver_later(wait: 30.second) #30秒後に送信

以上です!

【Android】Modelからの通知の実装方法における個人的な変遷まとめ

こんにちは。釘宮です。

AndroidにおいてModelからVC(View or Controller というか Acitivity or Fragment)に通知するときの方法が僕の中で変遷してきているなぁと思ったのでサンプルコードも書きつつ振り返ってみたいと思いました。

VCに全部書く

プログラミングを初めて間もないころ、なにも気にせずにVCに全部書いていましたすいません。
MVCとかよくわかってなかったので赴くままに書いていたわけです。

VC側

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // たとえばonCreateから呼ばれるとこにガリガリかいていたわけです
        ArrayList<Event> events = new ArrayList<Event>();
        :
    }

Callbackを使う

VCに全てを書ききるという初心者あるあるを抜け出したときはCallbackを使って実装するようになりました。
この方法はセッターを使ったり、もしくは引数としデータの取得完了時にCallbackでVCに通知する方法です。

たとえばEventを扱うEventModelを考えます。VC側でEventModel.requestGetAllを読んで、その結果をCallbackを用いて返す際、下記の手順を踏む事に成ります。

  1. EventModelにinterface Callbackを定義する
  2. EventModelでCallbackのメンバーを持ちセッターを用意する
  3. VCはrequestGetAllを呼ぶ前にCallbackをつくりEventModelにセットする
  4. VCからEventModel.requestGetAllを呼ぶ
  5. Modelは処理が終わったらcallback.onGetAllを用いてVCに通知する

実際は、データの取得に時間がかかる事が多くThreadなどを用いるためソースは下記のようになります。

Model側

public class EventModel {

    private static final int REQ_GET_ALL = 1;

    private Callback mCallback = null;
    
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case REQ_GET_ALL:
                    if (mCallback != null) {
                        mCallback.onGetAll((ArrayList<Event>)msg.obj);
                    }
                    break;
            }
        }
    };

    public void setCallback(Callback callback) {
        mCallback = callback;
    }

    public void requestGetAll() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                ArrayList<Event> events = new ArrayList<Event>();
                // ContentProviderだったりhttp通信だったりでeventsを取得する
                Message msg = Message.obtain();
                msg.what = REQ_GET_ALL;
                msg.obj = events;
                mHandler.sendMessage(msg);
            }
        }).start();
    }

    public interface Callback {
        void onGetAll(ArrayList<Event> events);
    }
}

VC側

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        EventModel eventModel = new EventModel();
        eventModel.setCallback(new EventModel.Callback() {
            @Override
            public void onGetAll(ArrayList<Event> events) {
                // 取得した後の処理
            }
        });
        eventModel.requestGetAll();
    }

この方法のデメリットは、たとえばデータの取得に時間がかかる場合にCallbackで通知したものの既にVCが死んでる可能性があるということです。無効なCallbackにアクセスすることでアプリが落ちる可能性がでてきます。

Observer Patternを使う

Callbackに飽きた頃、Martin Flowerさんに習いM->VCにObserver Patternを採用していました。これで無効なCallbackにアクセスすることはなくなります。

またまたEventを扱うEventModelを考えると下記の手順を踏むことになります。

  1. EventObserverを定義する
  2. EventModelでEventObserverのリストのメンバを持つ
  3. VC側でObserve開始時にEventModel.addObserveし、Observe終了時でEventModel.deleteObserverする
  4. VC側で取得完了時に呼ばれるonGetAllを定義する
  5. VCからEventModel.requestGetAllを呼ぶ
  6. Modelは処理が終わったらobserver.onGetAllを用いてVCに通知する

Model側のソースは基本的にCallback関係がObserverになっただけでそんなに変わりません。

Model側

public class EventModel {

     /** オブザーバーリスト */
    private CopyOnWriteArrayList<EventObserver> mObservers = new CopyOnWriteArrayList<EventObserver>();

    /**
     * オブザーバーの取得
     * @return オブザーバー
     */
    protected CopyOnWriteArrayList<EventObserver> getObservers() {
        return mObservers;
    }

    /**
     * Observerを追加
     * @param observer observer
     */
    public void addObserver(EventObserver observer) {
        mObservers.add(observer);
    }

    /**
     * Observerを削除
     * @param observer observer
     */
    public void deleteObserver(EventObserver observer) {
        mObservers.remove(observer);
    }

    private static final int REQ_GET_ALL = 1;
    
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case REQ_GET_ALL:
                    ArrayList<Event> events = (ArrayList<Event>) msg.obj;
                    CopyOnWriteArrayList<EventObserver> observers = getObservers();
                    for (EventObserver observer : observers) {
                        observer.onFetchedAllEvents(events);
                    }
                    break;
            }
        }
    };

    public void requestGetAll() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                ArrayList<Event> events = new ArrayList<Event>();
                // ContentProviderだったりhttp通信だったりでeventsを取得する
                Message msg = Message.obtain();
                msg.what = REQ_GET_ALL;
                msg.obj = events;
                mHandler.sendMessage(msg);
            }
        }).start();
    }
}

Observer

public interface EventObserver {
    void onGetAll(ArrayList<Event> events);
}

VC

public HogeActivity implements EventObserver {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // observerの登録
        mEventModel.addObserver(this);
        // どこか呼びたいタイミングで。ここじゃなくてもいい
        mEventModel.requestGetAll();
    }

    @Override
    public void onDestroy() {
        // observerを解除
        mEventModel.deleteObserver(this);
        super.onPause();
    }

    @Override
    public void onFetchedCache(ArrayList<Event> events) {
        // 取得した後の処理 
    }
}

デメリットはあるとすれば、ソースがなんか煩雑ってことかなと思います。

Rxを使う

最近流行のRxAndroidを使ってみてました。
ストリームの監視対象と監視する側のスレッドを選べるので今までのようなThreadやHandlerは出てこなくなるのでソースがきれいになります。
またまたEventModelを考えると手順は下記のようになります。

  1. EventModel.getAllStreamを実装しストリームを返すようにする
  2. VC側でCompositeSubscriptionのメンバを持つ
  3. VC側でストリーム監視開始時にそのストリームをCompositeSubscriptionに登録し、監視終了時にCompositeSubscriptionから外す
  4. VCからEventModel.getAllStreamを呼ぶ
  5. VCで取得したストリームをsubscribeする
  6. Model側は処理が終わったらsubscriver.onNextする

Model

public class EventModel {

    public rx.Observable<ArrayList<Event>> getAllStream() {
        return Observable.create(new Observable.OnSubscribe<ArrayList<Event>>() {
            @Override
            public void call(Subscriber<? super ArrayList<Event>> subscriber) {
                 ArrayList<Event> events = new ArrayList<Event>();
                // ContentProviderだったりhttp通信だったりでeventsを取得する
                subscriber.onNext(events);
                subscriber.onCompleted();
            }
        }).subscribeOn(Schedulers.newThread());
    }

}

VC側

public class RxActivity extends Activity {

    private final CompositeSubscription mCompositeSubscription = new CompositeSubscription();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Observable<ArrayList<Event>> eventListStream = eventModel.getAllStream();

        // Subscriptionの登録
        mCompositeSubscription.add(
                eventListStream.observeOn(AndroidSchedulers.mainThread())
                        .subscribe(new Action1<ArrayList<Event>>() {
                            @Override
                            public void call(ArrayList<Event> events) {
                                // 取得した後の処理 
                            }
                        }
                )
        );
    }

    @Override
    protected void onDestroy() {
        mCompositeSubscription.clear();
        super.onDestroy();
    }
}

デメリットはRxの学習コストが高い(オブジェクト指向の概念だけでは足りないところがある)ところだと思います。チームで使うとなるとチームのみんなが理解してないと使わない方がいいです。1人だけ理解しててもその人しか読めないっていう現象が発生します。 あとは個人的に思ってるだけなんですが、Rxが枯れていないというところかなと思います。少し使うだけならいいけど、相当な理解と使い続けるんだって言う意気込みとかないとM->VCとかの設計の大きなところで使うのは止めた方がいいかもしれないです。

EventBusを使う

EventBusをこの正月に使ってみたところ、すごくすっきり書く事ができました。またいままで挙げたようなデメリットもなく大変良いです。

ここでもEventModelを考えます。

  1. OnGetAllEventという取得完了用のクラスを用意する
  2. VCはonCreateなどで eventBus.registerし、onDestroyなどでeventBus.unregisterする
  3. VCは void onEventMainThread(OnGetAllEvent) を実装する
  4. Modelは処理が完了したら EventBus.getDefault().post(onGetAllEvent) でVCに通知する

Model側

public class EventModel {

    public void requestGetAll() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                ArrayList<Event> events = new ArrayList<Event>();
                // ContentProviderだったりhttp通信だったりでeventsを取得する
                OnGetAllEvent onGetAllEvent = new OnGetAllEvent();
                onGetAllEvent.events = events;
                EventBus.getDefault().post(onGetAllEvent);
            }
        }).start();
    }

}

イベント

public class OnGetAllEvent {
    public ArrayList<Event> events;
}

VC側

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EventBus.getDefault().register(this);
    }

    @Override
    protected void onDestroy() {
        EventBus.getDefault().unregister(this);
        super.onDestroy();
    }

    public void onEventMainThread(OnExitEvent event) {
        // 取得した後の処理 
    }

デメリットは今のところ特になにも感じてないです。

まとめ

まとめてみると結構スタイルが変わってきているんだなぁと改めて思いました。

そのときは正解でも、時代が変われば正解じゃなくなる事もあると思うのでこれからもアンテナを張り続けていければと思います。

それにしてもEventBusは学習コストも高くなく、イベントオブジェクトがParcerableをimplementしなければならないとかいう制約もないので本当に便利です。

非デザイナーが読んでおいて損はないデザイン本とかメディアとか。

こんにちは、太田です。

最近、当社の代表の秋貞がデザインましまし状態でめっちゃデザイン系の本とかサイトとか共有してくれるのですが、あまりまとめるのが好きじゃないようで事あるごとに「誰かまとめといて」的なことを言ってるので、今回は秋貞に代わって非デザイナーでも読んでおいた方がいい本とかWEBサイトとかを紹介したいと思います。僕の好みも入っているのでそこらへんに関してはご了承ください!

全部のせ

http://www.amazon.co.jp/gp/product/4839928401/ref=pd_lpo_sbs_dp_ss_1?pf_rd_p=187205609&pf_rd_s=lpo-top-stripe&pf_rd_t=201&pf_rd_i=1566091594&pf_rd_m=AN1VRQENFRJN5&pf_rd_r=1JMTHWH5KJSR6BR2Y7K3

http://www.amazon.co.jp/gp/product/4839928401/ref=pd_lpo_sbs_dp_ss_1?pf_rd_p=187205609&pf_rd_s=lpo-top-stripe&pf_rd_t=201&pf_rd_i=1566091594&pf_rd_m=AN1VRQENFRJN5&pf_rd_r=1JMTHWH5KJSR6BR2Y7K3

まずはこれ。3ヶ月前に僕が入社した直後から秋貞がずーっと絶対読んだほうがいいって言っていた本です。最初は中身も見ずに読んでいなかったのですが読んでからそれまで読んでいなかったことを後悔しました。タイトルには「non designer's」って書かれていますが、デザイナー初学者の人も絶対に読んだ方がいいと思います。大事なことだからもう1回言いますね。絶対に読んだほうがいいです。

http://www.amazon.co.jp/%E3%82%A8%E3%82%AF%E3%82%B9%E3%83%9A%E3%83%AA%E3%82%A8%E3%83%B3%E3%82%B9-%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88-%E9%95%B7%E8%B0%B7%E5%B7%9D%E6%81%AD%E4%B9%85-ebook/dp/B00APO69H4

http://www.amazon.co.jp/%E3%82%A8%E3%82%AF%E3%82%B9%E3%83%9A%E3%83%AA%E3%82%A8%E3%83%B3%E3%82%B9-%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88-%E9%95%B7%E8%B0%B7%E5%B7%9D%E6%81%AD%E4%B9%85-ebook/dp/B00APO69H4

これもけっこういろいろ衝撃的でした。「あ、だからアメリカのサイトが日本で必ず受け入れられるわけではないのね!」みたいなことが腹にすっと落ちる感じです。

マテリアルデザイン

Material Design

Googleマテリアル・デザインから学ぶ4つの重要ポイント + 参考UIデザイン、無料素材まとめ - PhotoshopVIP

http://www.100shiki.com/archives/2014/12/material_palette.html

http://www.100shiki.com/archives/2014/12/material_palette.html

当社ではデザインのモックアップをデザイナーチームと秋貞でよく作っているのですが、Googleマテリアルデザインを積極的に採用しているのと比例して、当社でもアプリのデザインをマテリアルデザイン的なテイストにすることが多いです。そんな時に役に立つのがここらへんのサイト。ほぼほぼ1つ目の方ばかり参考にしているのですが、他も便利だったりよくまとまってたりするので、マテリアルデザインを取り入れたい人は必見です。

配色とか

きれいに調和した色彩のカラーパレットを誰でもすぐ簡単に自動生成できる「Coolors」 - GIGAZINE

Webサービスの配色をどう決めるか / DENDESIGN – UI/UXデザインで価値を生み出す制作会社

ここらへんはあまり見ていないのでみなさんに使って頂いて逆に感想とか教えていただけると幸いです。

まとめ

僕もなんですが、プロジェクトに入るとわりと機能のほうに意識が傾きがちで、デザインがおざなりになりそうになることがよくあります。しかしユーザーが接するのは機能とデザインが組み合わさったものを使うわけで、それをデザイナーだけに丸投げっていうのは自分が作りました!って胸を張っ低うにはあまりにもリスクが高いし責任放棄かなと。

ということでエンジニアの人もそうでない人も、非デザイナーでWEBサービスアプリ開発に携わる人は是非参考にして頂ければ幸いです。 それではまた。

Capistrano3 + Rails4 + Unicorn + Nginx + EC2でサーバー構築!

みなさん、こんにちは。
入社2ヶ月目の佐野です。
今回はRailsで本番環境への以降の際、ハマった点が多かったのでみなさんと共有したいと思います。
間違っている点などがあればご指摘いただけると幸いです。

概要

EC2へデプロイし、とりあえず繋がるまで
情報がバラバラで調べるのにかなり時間が取られてしまったので、一連の流れをまとめました

このブログの対象者

Railsでのデプロイが初めての方

使用した環境

Rails 4.1.0 
Ruby 2.0.0-p576
rbenv 0.4.0 
Capistrano 3.2.1 
unicorn 4.8.3 
Nginx 1.6.2 
Mysql 5.5.40
EC2 Amazon Linux AMI 2014.09.1 (HVM)(プロダクションマシン) 
Git(リポジトリマシン)

デプロイ手順(サーバー側)

EC2にてインスタンスの作成

先にサーバー側の設定をします。
AWSサーバーにてEC2のインスタンスを作成します。

  • Amazon Web Servicesへログイン
  • EC2を選択
  • 左のサイドメニューのInstancesを選択
  • 真ん中のCreate InstanceのLaunch Instanceをクリック
  • Amazon Linux AMI 2014.09.1 (HVM)を選択
  • 使用するマシンの性能がずらずらと出てきます。

今回は初めてなので上から2番目のGeneral purposet2 smallを選択しました

  • NextConfigureInstanceDetailで次へ
  • 何もしないでNextAddStrageへ
  • 何もしないでNextTagInstanceへ
  • ここでインスタンスの名前を決めます(マシンの名前なので任意でOKです)
  • Configure Security Groupでファイアーウォールの設定をします。

最低でもMYSQL,SSH,HTTP,HTTPSの四つは許可しないとサーバーとの接続ができません。 
すでに設定してある方はそちらを使い、あとは自分の利用したい環境や必要に応じて
Customで作成しましょう。

  • 次に確認画面が出ますので良ければLaunchをクリック
  • キーペアの作成のモーダル画面が出ます

今使っているものを利用するか、新しく作るかが選択できますが、初めてなのでCreate new key pair
キーペアの名前を任意でつけてDownload Key Pairで自分のPCにダウンロードします。

  • Launch Instanceをクリックして完了

インスタンス作成直後は初期化処理が入るので数分待つ必要があります。
初期化が終わったらstatusrunningに変わります。
最後にElasticIPの設定をします。

  • 左メニューのElastic IPsを選択
  • 左上のAllocate New Addressをクリック
  • Yes Allocate

これで作成完了です。
「Instance」の一覧から、さきほど作ったインスタンスのPublic IPなどが確認できるのでコピーしておきます。

ローカルからEC2インスタンスへのログイン

次にローカルからEC2へログインできるようにします
インスタンス作成時にダウンロードしたキー(自分がつけた名前.pemのファイル)を他から見られないように
.sshディレクトリに移動します。
ファイルの権限を変更

chmod 400  ~/.ssh/自分のつけた名前.pem
ssh -i  ~/.ssh/自分のつけた名前.pem ec2-user@設定したElastic IP

これでPermission Denied(publock key)となるならchmod 600に変更する
これらのコマンドで以下の画面が出ればOK

__| __|_ )
_| ( / Amazon Linux AMI
___|\___|___|

初期設定ではec2-userというユーザーが作成されています。
これを自分で作成したユーザーに変更した方が良いのでユーザーを作成します。

ユーザー作成(EC2上での操作)

-rootユーザーしか作成ができないのでrootへ変更

$ sudo -su
useradd 任意の名前
$ cp -arp /home/ec2-user/.ssh /home/任意の名前/
$ chown -R 任意の名前. /home/任意の名前/.ssh
$ passwd 任意の名前

-sudo権限を付与する

$ sudo visudo
任意の名前 ALL=(ALL) ALL を追記
exitしてec2-userへ戻り作成したユーザーで入れるか確認

$ su - 作成したユーザー名
パスワード入力でログインできればOK

必要なものを順番にインストール

これらのコマンドで大体必要なものが入る
$ sudo yum update
$ sudo yum install -y gcc-c++ patch readline readline-devel zlib zlib-devel libyaml-devel libffi-devel openssl-devel make bzip2 autoconf automake libtool bison git

これからインストールするものは必ずローカル環境のバージョンと合わせるようにする

rbenvを入れる
cd
git clone git://github.com/sstephenson/ruby-build.git
cd ruby-build
sudo ./install.sh
cd
git clone git://github.com/sstephenson/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
source ~/.bashrc
exec $SHELL -l
rbenv install -l

自分が開発で使ったrubyのバージョンを指定しないとダメ
rbenv install 2.0.0-p576;rbenv rehash
rbenv global 2.0.0-p576

ちゃんと入ったか確認
$ git --version
git version 2.1.0
$ ruby -v
ruby 2.0.0−p576
$ which gem
~/.rbenv/shims/gem
$ which ruby
~/.rbenv/shims/ruby

bundlerを入れてRailsをインストール
bundlerもバージョン合わせる(最新を使えばほぼ問題無し)
$ gem install bundler --no-rdoc --no-ri
Successfully installed bundler-1.7.9
$ sudo rbenv rehash
$ gem install rails -v 4.1.0
$ rbenv rehash
$ rails -v
Rails 4.1.0
$ which rails
~/.rbenv/shims/rails

Mysqlを入れる
$ sudo yum install mysql-server mysql-devel
$ sudo service mysqld start
$ mysqladmin -u root password '新しいパスワード'
$ mysql -u root -p

ログインできるか確認
ログインできればそのまま次に設定を行う

Mysqlの設定(ユーザー、データベース作成)

mysql> GRANT ALL PRIVILEGES ON *.* TO '任意のユーザー名'@'設定したElasticIP' IDENTIFIED BY 'パスワード決める' WITH GRANT OPTION;
mysql> FLUSH PRIVILEGES;
作れたか確認
mysql> select Host, User, Password from mysql.user;
データベース作成
mysql> CREATE DATABASE 任意のデータベース名 CHARACTER SET utf8;
作れたか確認
mysql> show databases;
終了
mysql> quit

アプリをデプロイするディレクトリを作成
現在のディレクトリ確認
$ pwd
/home/ec2-user
デプロイは/var/www以下に作成することにしました。
$ mkdir -p var/www/あなたのアプリ名

Nginxを入れる
$ sudo yum -y install nginx
起動確認
$ sudo /etc/init.d/nginx start
設定ファイルを編集
$ sudo vi /etc/nginx/nginx.conf

events {
    worker_connections  2048;
}
#通信情報
http {
     #最新のアプリはcapistranoがcurrentに最新のデプロイしたアプリのシンボリックリンクが貼られるのでそこを指定すればOK
    root  /var/www/あなたのアプリ名/current;
    #unicornに必要
    #http{}の中に記述しないと動かない
    upstream unicorn-server {
        server unix:/var/www/あなたのアプリ名/shared/tmp/sockets/unicorn.sock
        fail_timeout=0;
    }
    #unicorn-serverという名前は任意でOK。プロキシで設定する名前と同じなら大丈夫
#サーバー情報
    server {

        listen 80;
        client_max_body_size 4G;
        server_name あなたのEC2のpublic IP;
        keepalive_timeout 80;
     #ログ関係は設定しないとデバッグが不可なので必須(下記はデフォルトのフォルダを指定しているので作成する必要はない)
        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;

        root  /var/www/あたなのアプリ名/current;
#本番環境ではrailsのpublic以下のassetが使用されるのでそこを指定
        location ~ ^/assets/ {
            include /etc/nginx/mime.types;
            root    /var/www/あなたのアプリ名/current/public;
        }
       location / {
            proxy_pass http://unicorn-server;#ここのunicorn-serverという名前をupstreamと合わせる必要がある
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $host;
        }
#エラー画面の場所(railsのディレクトリを指定する)
        error_page   500 502 503 504  /500.html;
        location = /500.html {
            root /var/www/teamhacker/current/public;
        }
    }
}
これが終わったら:wqで保存して再起動
$ sudo service nginx restart
stop,start [OK]が出ればOK
出なかった場合は設定が間違っているのでログを見ながら直す

デプロイ手順(ローカル側)

ここまで終わったら次はローカル側の設定をします。
$ exit
でEC2サーバーからログアウトします。

デプロイするために追加したGem

group :production, :staging do
  gem 'unicorn'
end
group :development do
  gem 'capistrano', '~> 3.2.1'
  gem 'capistrano-rails',   '~> 1.1', require: false
  gem 'capistrano-bundler', '~> 1.1', require: false
  gem 'capistrano-rbenv', '~> 2.0', require: false
  gem 'capistrano3-unicorn'
end
bundle exec bundle install
Capistranoの設定ファイルを生成
bundle exec cap install STAGES=staging,production

Capfileを編集

require 'capistrano/setup'
require 'capistrano/deploy'
require 'capistrano/rails'
require 'capistrano/rbenv'

Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }

Deploy.rbを編集

set :application, "あなたのアプリ名"
set :repo_url, 'あなたのgitのレポジトリ名'#gitからコードをcloneする
set :branch, 'master' #マージ前なら他のブランチでも設定可能
set :deploy_to, '/var/www/EC2で作ったディレクトリ名'
set :keep_releases, 5 #接続を確保して同時接続を高速化するための設定。アクセス数に応じて変える必要あり
set :rbenv_type, :user
set :rbenv_ruby, '2.0.0-p576'     #rubyのバージョン間違えないように!
set :rbenv_map_bins, %w{rake gem bundle ruby rails}
set :rbenv_roles, :all
set :linked_dirs, %w{bin log tmp/backup tmp/pids tmp/cache tmp/sockets vendor/bundle}

namespace :deploy do

  desc 'Restart application'
  task :restart do
    on roles(:app), in: :sequence, wait: 5 do
      # Your restart mechanism here, for example:
       execute :touch, release_path.join('tmp/restart.txt')
    end
  end

  after :restart, :clear_cache do
    on roles(:web), in: :groups, limit: 3, wait: 10 do
      # Here we can do anything such as:
      # within release_path do
      #   execute :rake, 'cache:clear'
      # end
    end
  end
  after :finishing, 'deploy:cleanup'
end

config/unicorn.rbの編集

application = 'reserve-hacker'

worker_processes 2 #EC2で作ったAmazonLinuxのCPU数より少し大きく
app_path = "/var/www/EC2で作ったディレクトリ名"
#標準だとsharedに作成される
#ここが一番重要
#Nginxのupstreamで設定した「server unix:/var/www/あなたのアプリ名/shared/tmp/sockets/unicorn.sock」の場所と合わせる!!
listen "#{app_path}/shared/tmp/sockets/unicorn.sock"
pid "#{app_path}/current/tmp/unicorn.pid"

#何秒でタイムアウトするか
timeout 60

#ダウンタムをなくす
preload_app true

stdout_path "#{app_path}/current/log/production.log"# 標準出力ログ出力先
stderr_path "#{app_path}/current/log/production.log"# 標準エラー出力ログ出力先

GC.respond_to?(:copy_on_write_friendly=) and GC.copy_on_write_friendly = true

config/deploy/producution.rbの編集

set :stage, :production
set :rails_env, 'production'
server 'EC2のElasticIP', user: 'EC2で作成したユーザー名(rootのユーザー。Mysqlとは違うよ)', 
roles: %w{web app db}  #何のサーバーに処理をさせるのか。今回は同じサーバーで全部動かすのでweb app db全て指定
#sshでEC2に入るのに必要
set :ssh_options, {
   keys: [File.expand_path('~/.ssh/EC2で任意でつけてダウンロードしたキー名.pem)')]
}

database.ymlの編集

#ここをEC2のサーバー側で作ったMysqlのユーザー名、パスワード、ホスト名を書く
production:
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: EC2で作ったmysqlユーザー
  password: EC2で作ったユーザーのパスワード
  host: EC2のElasticIP
  database: あなたが作ったデータベース名

もともとMysqlで開発していたのであればrailsのdatabase名をコピーしてからEC2に入って作った方が早いです。
そちらの方が間違いが少ないです。
名前とかで間違えると後から大変なのできちんと確認しながら設定するようにしてください。

ここまで来たらあとは実際にデプロイしてみて動くかどうか確認してみましょう!
デプロイ実行コマンド

bundle exec cap production deploy

なお今回はstagingとproductionを分けないで、いきなりproductionでデプロイしてます。
stagingでデプロイする場合は

bundle exec cap staging deploy

となります。
config/deploy/prodcution.rbの内容をconfig/deploy/staging.rbにコピーすることも忘れないようにしてください。

長くなりましたがお付き合いいただきありがとうございました。
私の場合はprecompile等のエラーが出たのでCSS等は反映されていませんがなんとか動きました。
その辺りのエラーも解消できれば追記したいと思います。
みなさんのデプロイにかける時間が短縮することを願っております。

最後にデプロイでよく使うコマンドの一覧を書いておきます。
お役に立てば幸いです。

ステージング環境へデプロイ
$ bundle exec cap staging deploy
ステージング環境へデプロイ
$ bundle exec cap production deploy
unicornが起動しているか確認
$ ps aux | grep unicorn
unicornをデーモンで起動
$ bundle exec unicorn -c config/unicorn.rb -D
サーバー側でのnginxの設定ファイルを編集
$ sudo vim /etc/nginx/nginx.conf
サーバー側でのnginxのエラーログを確認
$ sudo vim /var/log/nginx/error.log
サーバー側でのrailsのエラーログを確認
$ vi /var/www/あなたのアプリ名/current/log/production.rb

素晴らしきハッカー

こんにちは、釘宮です。

ハッカーと画家」の「素晴らしきハッカー」を超解釈 + 超要約すると下記のような事が書いてあります。

  • どれだけ給与をもらえるよりかはそこで何をするかがハッカーにとって大事。問題をより面白い問題に再定義することでハッカーたちを駆り立てろ。
  • 良いハッカーはなんでもコントロールしたがる。OSでさえ。
  • 良いハッカーPythonを好む事が多い。
  • ハッカーは考えを中断されるかもしれないという可能性だけで、難しい問題を考えようという気が起こらなくなる。
  • あなたがプログラマでない場合のハッカーの管理方法については一言だけ。「あきらめろ」
  • 良いハッカーは良いハッカーを好む。
  • ハッカーが優秀かどうかを見分ける方法はわからない。そもそも良いハッカー自身が自分を優秀と自覚していない事がほとんどである。あなたがハッカーで一緒に仕事をすることで始めてわかるかもしれない。
  • 良いハッカーになる鍵は、たぶん、自分がやりたいことをやることだ。

触発されて私なりに優秀なハッカーについて考えてみました。

優秀なハッカーが実行している10のこと

環境、開発者の年齢によって優秀の定義は変わってきます。
今回は若手でスタートアップで働いている自分の周りに居る優秀なハッカーたちの共通点をあげてみました。

抽象的な資質ではなく具体的な行動のみとしています。

1.何かしらのモノを作っている

優秀だと思う人の中でこれをやって居ない人は1人もいないです。

2.プログラミングが好きなので平日夜でも土日でもやる

仕事に疲れて帰ってきてすぐ自分が作ってるものを作り始めたり、 土日に勉強会に行ったりとそんな方が多いです。
プログラミングそのものが好きなパターンとモノ作りが好きなパターンがあるのではと以前は思っていたのですが、 そうではなくプログラミングそのものもモノ作りそのものもどっちもが好きな方が多い気がします。

3.複数の言語を習得している(または読むのに抵抗を感じない)

たとえばAndroidiOSアプリを作るにしてもサーバー側が必要になる事が多いので自ずと多言語使える人が多いです。
また好奇心が強い為か新しい技術への情報への関心が強い方が多いです。

ただ、メインにしている言語の知識はとりわけ深いです。

4.コミュニティに所属している

まさに「良いハッカーは良いハッカーを好む」です。 ハッカーに限らず優秀な人の周りには優秀な人があつまると言いますが、まさにそうだと思います。
コミュニティの中で情報共有、切磋琢磨して自分の位置を知って技術を磨いている方が多いです。

(ただコミュニティに属しているからこそ優秀だと認知されているだけで、本当はコミュニティに属してなくても優秀な人はいるのかも。。)

5.技術書をめっちゃ持ってる

気になったら即ポチです。

6.FacebookよりTwitterを使う

僕は半々でつかってますしFacebookの方をよく使う方も居ますが、比率的には断然Twitterが活発な方が多いです。 よくイベントでハッシュタグが用意されている事が原因かもしれません。

7.Qiitaやブログへ積極的に投稿している

積極的に情報を提供しています。 提供する事で得られるレスポンスから学んだり、それによって同じハッカーに評価される事をモチベーションとしています。

8.ツールにこだわって使いこなす

VimだったりEmacsだったり、またIDEでもエディタでもショートカットキーを徹底的に使いこなします。 ただ受託系出身の人は現場によって使えるツールが異なるのでツール自体への関心が薄い場合もあります。私もそうでした。

9.何かと自動化を考える

人手で何度もやる作業に関しては自動化をはかりたがります。 「自動化する」ではなく「自動化を考える」としたのは自動化のコストを考えて、そのコストの方が軽いと判断したときに始めて自動化するからです。 コストが見合わない場合は「自動化しない」という判断も彼らは行います。

10.よくコードを読んでいる

ただの好奇心からOpengrokでAndroidフレームワークを読んだり、githubのソースを読んだりしている人が多いです。 コードリーディングはいろんな学びがあるので、本当におすすめです。

まとめ

私が優秀だと思うハッカーたちは知識に人一倍どん欲であって、加えて必ず何かしらのアウトプットをしています。
それによって知識のサイクルをまわしているような節が感じられます。

もちろん、これ全てに当てはまるからと言って優秀とは限りません。
各々が思う「素晴らしきハッカー」像を考えて、それに向かってできることをやっていけば良い訳です。
ただ、今回あげた10の行動がその際のお役に立てば幸いです。

iPhone標準カレンダーでなぜかGMTが表示される件について

はじめまして、ジェネストリームでiOSアプリを開発している本間です。

みなさん、iPhone使ってますか? 日本は世界の中でもiPhoneのシェアが高い国なので、iPhoneを使われている方は多いと思います。 iPhoneといえばメールやカレンダー、メモなどの標準アプリが充実しており、アプリなんでダウンロードしなくても標準アプリで十分だという人もいるでしょう。 しかし、そんなiPhone標準カレンダーで表示が何かおかしいという問題があったので、少し調べてみました。

iPhone標準カレンダーにおける謎のGMT表示

f:id:genestream:20141204144905p:plain

これがiPhoneの標準カレンダーの画面なのですが、予定のところに何か違和感がありませんか? そうです。特に海外に縁があるわけでもないのにGMTの表示があるんです。

GMTとはグリニッジ標準時刻(Greenwich Mean Time)のことで、時差を考える際に基準となる時刻のことです。)

表示されている予定の時間は正しいので問題は無いのですが、関係のないGMTの時間が書いてあるとなんだこれはとなる訳です。 危機管理能力が高い人なら、万が一にも急いでいるときにGMTの方の時間を見てしまえば何か問題が起きるかもしれない。意味がないのなら消してしまいたい。と思いますよね。

僕はそう思いました。そこで、iPhoneだから設定でこんなのちょいと消せるだろうと設定画面にいきました。 タイムゾーンや言語設定など様々いじってみましたが、一向にGMTが消えないんです。

(; ・`ω・´)ナン…ダト!?

どうしたらいいんだー!ということで調べると、いくつかわかったことがあるのでまとめたいと思います。

GMTが表示される条件

よくよくカレンダーを見てみるとGMTが表示されていない予定があることに気付きました。 この違いは何だということで調べると、GoogleOutlookと同期している予定だとGMTが表示され、iPhoneから登録した予定にはGMTが表示されないということがわかりました。しかし、たとえGoogleと同期している予定でも繰り返し予定のときはGMTが表示されないんです。

ちょっとよくわからないですね。。 わかりやすいように表にまとめてみました。

登録デバイス 登録先 リピート GMT表示
iPhone iCloud あり
無し
Google, Outlookなど あり
無し
PCや他のiPhone, iPad iCloud あり
無し
Google, Outlookなど あり
無し ⚪︎

表にまとめるとまとめるまでもなかったような結果になりましたね。iPhone以外のデバイスからGoogleなどのサービスを利用して繰り返しでない予定を登録するとGMTが表示されるということですね。

GMT表示に対するネット上の皆様の見解

このGMT表示、iPhone4から約4年iPhoneを使っている私がなぜ今まで気づかなかったのかと思ったのですが、iOS8から表示されるようになったみたいですね。

ネット上ではこの謎機能について議論が活発にされており、結構みなさん消したいと思っているようでした。

iOS 8 Calendar on iPhone showing GMT time… - Apple Community

Calendar is showing GMT after iOS 8 update - Apple Community

発見された当初は何が原因なのかわからないため様々な可能性が疑われていましたが、iOS8に原因があるという結論でした。 その後これはiOS8のバグだと言われていましたが、一向に解消されないのでもしかしてこれが仕様なのではないかという意見も出る始末です。 Appleは修正する気がないのではないかというのが、みなさんの考えのようでした。

GMTの消し方

さて、ここまでAppleの謎のGMT表示について調べたことを書いてきましたが、いよいよその消し方です。

その消し方ですが、 基本的にはありません。ノ( ̄0 ̄;)\オー!!ノー!!!!

基本的にと言ったのは、Google Appsユーザーの方向けのGMTの消し方しか見つからなかったからです。

しかし!! Google Appsユーザーでない方でどうしても消したいという方もいるでしょう。そのような方向けに僕が超強引な超面倒くさい解決策を考えました!パチパチパチ o(^ー^)o☆o(^ー^)oパチパチ

GMT表示の消し方① 〜Google Appsユーザー向け〜

※僕はGoogleAppsのアカウントを持っていないので検証できていません。この方法で無理だった場合はお知らせください。

1. 設定>メール/連絡先/カレンダー>アカウントを追加を選択

2. サービスの中から、Exchangeを選択

f:id:genestream:20141204162722p:plain

3. メールにGoogleAppsのメールアドレス。パスワードにパスワードを入力して次へ。

f:id:genestream:20141204163027p:plain

4. サーバにm.google.com。ユーザ名にメールアドレスを入力して次へ。(注意: m.google.comにアクセスするためには言語をEnglish (US)にする必要有り)

f:id:genestream:20141204163134p:plain

5. カレンダーにチェックが入っていることを確認して保存。

これでGMTの表示を消せるようです!

[参考HP] iOS 8 Calendar on iPhone showing GMT time… - Apple Community

GMT表示の消し方② 〜どうしてもどうしてもGMTを消したい方向け〜

こちらはGoogleAppsユーザーに限らず誰でもできます!

しかし、超面倒くさいのでそこまでしてでもGMTを消したいんだ!という方のみ行ってください!

その方法とは、ずばり、今日から今日まで繰り返すような繰り返し予定にする!ことです。

前述の通り繰り返し予定はGMTが表示されません。このことを利用した方法ですね! 繰り返しの方法として、指定日まで繰り返すという方法があります。以下のように、指定日をそのイベントの日にしてしまえば、1回しか表示されない繰り返しイベントが作成されますよね。これで超強引で超面倒ですがGMTを消すことができます!

f:id:genestream:20141204164525p:plain

全ての予定を繰り返しに設定する手間よりもGMTをとにかく消したいんだ!という方は是非この方法でGMTを消してください!

僕は絶対嫌なので最後にもう一つだけGMT問題を解決する方法をご紹介します。

GMT表示の消し方③

それは、別のアプリを使うことです。

カレンダーアプリはいろいろあるので、いっそのこと他のアプリに乗り換えるというのが正しい判断な気もします。 今は様々なアプリがあるので使いづらいところがあるのであれば、それより良いアプリを探すというのが正攻法だと思います。

そこで、オススメのカレンダーアプリ1選!

ジェネストリームのCu-hackerです!カレンダーアプリに悩んでいる方は是非ダウンロードしてみてください!シンプルなGoogleと同期できるカレンダーですので、GoogleCalendarを利用している方は今すぐ使うことができます!

使ったことのない方はぜひダウンロードして使ってみてください!

https://itunes.apple.com/jp/app/5miaodesakuttosukejuru-diao/id864027744?mt=8&at=10l8JW&ct=hatenablog

AndroidでActionBar.Tabを使わずにタブナビゲーションを実装する

こんにちは徳山です。

ActionBarの変更

Android 5.0からActionBarの代わりに使うToolBarが追加されました。 ToolBarはLayout内に書くので中に入れる要素をカスタマイズするのがやりやすくなりました。

同時にActionBar.Tabが非推奨になっています。その代わりに使える新しいAPIは特に提供されていないので自分で実装する必要があります。 どう実装するのがいいか調べてみました。

方法

PagerTabStripを使う

GoogleのSampleのSlidingTabStripやSlidingTabLayoutを使う

Googleのサンプルです。ファイルをプロジェクト内にコピーして使います。

PagerSlidingTabStripを使う

GitHubで公開されているライブラリ。Material Designに対応しています。

実装

今回はPagerSlidingTabStripで実装してみました。 ほとんどGitHubのREADMEそのままです。

Gradleファイルに以下を追加

    compile 'com.jpardogo.materialtabstrip:library:1.0.6'

レイアウトのToolbarの下にPagerSlidingTabStrip widgetを追加する

    <android.support.v7.widget.Toolbar
        android:id="@+id/tool_bar"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:minHeight="?attr/actionBarSize"
        android:background="?attr/colorPrimary">
    </android.support.v7.widget.Toolbar>

    <com.astuetz.PagerSlidingTabStrip
        android:id="@+id/tabs"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"/>

ActivityのonCreateでViewPagerにtabをバインドする

        PagerSlidingTabStrip tabs = (PagerSlidingTabStrip) findViewById(R.id.tabs);
        tabs.setViewPager(mViewPager);

f:id:genestream:20141203102101p:plain

以上です。これだけで簡単にMaterial Designなタブナビゲーションが実装できました。