【Rails4】kaminariをAPIで利用する

ページネーション用Gemで有名なkaminari。
ただ、使い方を調べてもAPIでの利用方法が見つからなかったので記載。

前提
サンプルとしてTodoをJSONで渡すAPIを実装

下記Gem導入済み
・kaminari
・active_model_serializers

modelの出力フォーマットをactive_model_serializersを利用して設定

./app/serializers/todo_serializer.rb

class TodoSerializer < ActiveModel::Serializer
  attributes :id, :body, :memo, :complete, :user_id
end


kaminariの共通設定ファイルを定義

config/initializers/kaminari_config.rb

Kaminari.configure do |config|
  config.default_per_page = 7    #最大項目数
  # config.max_per_page = nil       #最大数/page
  # config.window = 4               
  # config.outer_window = 0
  # config.left = 0
  # config.right = 0
  # config.page_method_name = :page
  # config.param_name = :page
end
Contact GitHub API Training Shop Blog About


kaminariをAPIに適用させる

config/initializers/active_model_serializer.rb

ActiveModel::Serializer.config.adapter = :json_api


controllerを実装する

class TodosController < ApplicationController

  def index
    #deviceを利用していますが、ここは各自読み替え
    todos = current_user.todos.page(params[:page] ||= 1)
    
    #meta 以下が今回の設定を適用させる
    render json: todos, meta: pagination_dict(todos)
  end

#以下省略

出力確認

{
"data":[{"id":"11","type":"todos","attributes":{"body":"APIを実装する","memo":"","complete":false,"user-id":9}},  {"id":"12","type":"todos","attributes":{"body":"はてなに投稿する","memo":"","complete":false,"user-id":9}},{"id":"13","type":"todos","attributes":{"body":"記事を投稿する","memo":"","complete":false,"user-id":9}}],
"links":{},
"meta":{"current-page":1,"next-page":null,"prev-page":null,"total-pages":1,"total-count":3}
}

meta 及び links がnodeに存在すれば完了。

【Rails4】before_actionに引数を渡す

以下の様にbefore_actionに引数を渡した状態で定義してもエラーとなる。

before_action :test('hogehoge')

これは以下の様に修正することで解決できる。

before_action -> {
  test('hogehoge')
}


フィルターを設定したい場合は以下の様に追記。

before_action -> {
  test('hogehoge')
},only: [:index, :show]


少しハマったのでメモ。

【Rails4】Devise::MissingWarden エラーへの対処

RepecでControllerのテストを実行した際に発生。
以下エラー文

Devise::MissingWarden:
 Devise could not find the `Warden::Proxy` instance on your request environment.
Make sure that your application is loading Devise and Warden as expected and
 that the `Warden::Manager` middleware is present in your middleware stack.


原因
Device gem によるプロキシエラー。

対応

f you're using RSpec, you can put the following inside a file named spec/support/devise.rb or in your spec/spec_helper.rb (or spec/rails_helper.rb if you are using rspec-rails):

RSpec.configure do |config|
  config.include Devise::Test::ControllerHelpers, type: :controller
  config.include Devise::Test::ControllerHelpers, type: :view
end

とのことなので以下の様に設定を追加

spec/rails_helper.rb

RSpec.configure do |config|
  config.include Devise::Test::ControllerHelpers, type: :controller
  config.include Devise::Test::ControllerHelpers, type: :view
end

【Java】SSL通信を実装する

環境
作業対象ファイル: C:\ssl
JDKのパス: C:\Program Files\Java\jdk1.6.0_45\bin
対象のサーバー証明書名: sample.cer

keyStore と trustStoreとは?
keystore: サーバーに送信するクライアントの証明書を格納するファイル。
trustStore: クライアント側が認証するサーバー側の証明書を格納するファイル。

手順
KeyStoreとTrustStore保存用ディレクトリを作成(C:\ssl)

認証対象のサーバー証明書(sample.cer)を C:\ssl に配置

ターミナルをAdministrator権限で実行し、インストール済みのJDK(C:\Program Files\Java\jdk1.6.0_45\bin)に移動。

以下のコマンドでkeyStoreを新規作成 -storepass の引数がパスワードとなります。

$ keytool -genkey -keystore keystore -storepass hogehoge

※この際、色々と設定を聞かれますが、よしなに...


同じくtrustStoreを新規作成

$ keytool -genkey -keystore truststore -storepass hogehoge


続いて sample.cer を trustStore に以下のコマンドでインポート -alias の引数が管理名として登録されます。

$ keytool -import -trustcacerts -file C:/ssl/sample.cer -keystore "C:/ssl/truststore" -alias sample_ssl


インポートされているかを以下のコマンドで確認

$ keytool -v -list -keystore  "C:/ssl/truststore"


インポートされている証明書の一覧が出てくるので、今回追加した sample_ssl が存在していれば成功。

以下サンプルコード

    /**
     * 認証付SSLContext作成
     * @param key_path Keystoreファイルのpath
     * @param key_password Keystoreファイルのpassword
     * @param trust_path Truststoreファイルのpath
     * @param trust_password Truststoreファイルのpassword
     * @return
     * @throws Exception
     */
    private SSLContext ssl_auth(String key_path, String key_password, String trust_path, String trust_password) throws Exception{
        //KeyStore読み込み
        char[] key_pass_char = key_password.toCharArray();
        KeyStore key_store = KeyStore.getInstance("JKS");
        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");

        key_store.load(new FileInputStream(key_path), key_pass_char );
        kmf.init(key_store, key_pass_char);

        //TrustStoreの読み込み
        char[] trust_pass_char =TrustPass.toCharArray();;
        KeyStore trust_store = KeyStore.getInstance("JKS");
        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");

        trust_store.load(new FileInputStream(TrustPath), trust_pass_char);
        tmf.init(trust_store);

        KeyManager[] key_managers = kmf.getKeyManagers();
        TrustManager[] trust_managers = tmf.getTrustManagers();

        SSLContext sslcontext = SSLContext.getInstance("TLS");
        sslcontext.init(key_managers, trust_managers, null);

        return sslcontext;
    }


     URL urlObj = new URL(url);
     HttpsURLConnection http = (HttpsURLConnection) urlObj.openConnection();
     http.setRequestMethod("POST");
     http.setDoOutput(true);
     http.setConnectTimeout(30000); 
     http.setReadTimeout(30000); 
     http.setSSLSocketFactory(ssl_auth("C:/ssl/keystore", "hogehoge", "C:/ssl/trustStore", "hogehoge").getSocketFactory());
     http.connect();

     OutputStream os = http.getOutputStream();
     PrintStream ps = new PrintStream(os);
     ps.print("送信するパラメータ");
     ps.close();

【javascript】ES6で導入されたclassにクラスメソッドを実装

ES6で導入されたclass記法は元々あった擬似クラス構文のシンタックスシュガー。
そのため、ES5時代の手法が そのまま転用できる。

class Person{

  constructor(){
     this.name = '山田太郎'
  }
  
  say(){
    console.log(this.name);
  }
}

今回定義したPersonクラスにクラスメソッドを追加する。

Person.method = function(){
   console.log("クラスメソッド");
}


これだけ。
実際に試してみる。

let tarou = new Person();

//インスタンスからクラスメソッドにアクセスできない
tarou.method()  //Uncaught TypeError

//インスタンスはインスタンスメソッドにアクセスできる
tarou.say()    //山田太郎

//クラスはインスタンスメソッドにアクセスできない
Person.say()    //Uncaught TypeError

//クラスはクラスメソッドにアクセスできる
Person.method()  //クラスメソッド


ES5での擬似クラス定義を理解していれば然程難しくはない。

React.jsで子から親へ イベントを通知する

コンポーネントメソッドをコールバック実行するメソッド
コンポーネントのpropsに設定するればイベントの通知が可能。

まずイベントを発生させる子コンポーネントを定義する。

var CommentForm = React.createClass({
  clickEvent(e){
    var cast_value = "渡す値";
    this.props.onEventCallBack({ message : cast_value });
    return 
  },
  render : function(){
    return (
        <div>
          <button onClick={this.clickEvent}>click</button>
        </div>
        )
  }
});

次にイベントを検知する親コンポーネントを定義。

var CommentArea = React.createClass({
  
  pushMessage : function(comment){
    console.log(comment);
  },
  render : function(){
    return (
        <div>
          <CommentForm onEventCallBack={this.pushMessage}/>
        </div>
        )
  }
});

これでCommentFormでクリックイベントが発生した際に
「渡す値」がconsole出力される。

Express4 & React.js 環境を構築

React.js開発環境でググるとBabelとかnpm-scriptsやら色々出てきて
軽くお試しで作るのには色々と面倒なので簡単な環境構築をする。
※ちなみにExpress4のテンプレートを利用します。

とりあえず前提条件で以下のものは導入済みのこと
・npm
・node.js

react-tools のインストール

$ npm install -g react-tools

各ディレクトリの準備
まずJSXファイルを保存するディレクトリを作成する。
今回は public/jsx を作成

続いてjsxのコンパイル先ディレクトリを作成。
これに関してはpublic/javascript/ で問題ない。

これで以下のコマンドを実行すれば自動的にjsxファイルが jsファイルに変換される。

$ jsx -x jsx ./public/react ./public/javascripts/

シェルスクリプトに纏める
このままいくとjsxを編集する度にコンパイルが必要なのでシェルを作成する。
ついでに起動用のコマンドを追記しておく。

start.sh

jsx -x jsx ./public/react ./public/javascripts/
node app.js↲
npm start

後は起動する際に以下のコマンドを実行する。

$ sh start.sh

これでReactの環境構築は完了。
本格的にやるならBabelとかnpm-scriptは必要。