Skip to content

Instantly share code, notes, and snippets.

@monmon
Created June 18, 2012 15:41
Show Gist options
  • Save monmon/72c2343ec862940c661d to your computer and use it in GitHub Desktop.
Save monmon/72c2343ec862940c661d to your computer and use it in GitHub Desktop.
Chanko勉強会
  • 今日の目標
    • Chankoを使って特定のユーザには違う機能を出す
  • 今日の流れ
    1. Chankoとは
    2. Chanko概要
    3. Chankoの導入
    4. その他

Chankoとは

  • Cookpadが本番で使っているRailsの拡張機能
  • 特徴
    • 安全:障害が発生した場合も影響を最小限に抑える
    • 高品質:メインのコードと区別することで、低品質と高品質のコードを使い分ける
    • 速い開発:プロトタイプで作成中のコードを機能単位で実装
  • ざっくり言うと
    • Chankoを使う前は大きな機能を大きくリリース before_chanko
    • Chankoを使ってからは小さく早くリリースして計測して安全に大きなリリース after_chanko

Chanko概要

  • 例:新しい検索ボタンを付けたい場合

安全性

  1. 一部ユーザには新しい検索ボタンを見せる
    new_search

  2. もしraiseしたら?
    raise

  3. その場合にはdefaultの機能が出るように制御されている
    default_search

品質性

  • Chankoで作られる機能はapp/units/にひとまとめにされる unit
    • テストの状態が一目瞭然(rcoverage)
    • 必要ない機能であれば簡単に削除

開発の楽さ

  • Unit Scriptの中身
    impl
  1. active_ifで「誰に対して有効にするか?」を定義
    active_if
    • contextにはcontollerのコンテキストが入っている
  2. 有効になった時のロジック(たとえばviewの場合)
    scope_view
    • scopeでviewやcontroller単位でfunctionを作れる
  3. 元々のsearchボタンが以下のようにrenderされていた場合には
    default_view
  4. invokeをそこに置くことでchankoが呼ばれる
    invoke
    • raiseしたり、無効な状態ではdo以下が実行される
  5. invokeの第一引数がmoduleで第二引数がfunction
    invoke_view
  6. これで無効な状態(一般ユーザ)と有効な状態(staff)とで表示が変わる
    chanko_result

Chankoの導入

  1. まずはrailsアプリを始める
% rails new chanko_app
  1. Gemfileにchankoを追加
# vim Gemfile
gem 'chanko', :git => 'git://github.com/cookpad/chanko.git'
gem 'devise'                    # 特定ユーザに対しての処理を試したいのでdevise
  1. bundle installでgemをインストール
% bundle install
  1. アプリにchankoをインストール
% rails generate chanko:install
 initializer  chanko_initializer.rb
         run  ln -ns ../app/units test/units from "."
      create  lib/chanko/active_if
      create  lib/chanko/active_if/active_if.rb
* active_if.rbが作られる。中身はactive_ifのためのdefine
# cat lib/chanko/active_if/active_if.rb
Chanko::ActiveIf.define(:always_true) do |context, options|
  true
end

Chanko::ActiveIf.define(:always_false) do |context, options|
 false
end

Chanko::ActiveIf.define(:not_production) do |context, options|
 !Rails.env.production?
end
    * これ以外にも発動させたい条件を定義したい場合には``lib/chanko/active_if/main.rb``に追加すればいい  
# 例えばstaffだけ有効にしたい機能を付けたい場合には:staffを定義
Chanko::ActiveIf.define(:staff) do |context, options|
  user = options[:user] || context.instance_variable_get('@login_user')
  next false unless user
  next false unless user.staff?
  next true
end
  1. chankoを利用できるようにapp/helpers/application_helper.rbを以下のように追加
module ApplicationHelper
    include Chanko::Invoker
    include Chanko::Helper
end
  1. ここまでの作業でrails generate chanko hogeで「hoge」という機能をchankoを通して使えるようになる

  2. monmonという機能(Chanko Unit)を作ってみる

% rails generate chanko monmon
      create  app/units/monmon/monmon.rb                  # このファイルの中にModel、Controller、Helper、Viewのロジックを書く
      create  app/units/monmon/views/_show.html.haml
      create  app/units/monmon/specs/controllers/monmon_controller_spec.rb
      create  app/units/monmon/specs/models/monmon_model_spec.rb
      create  app/units/monmon/specs/helpers/monmon_helper_spec.rb
      create  app/units/monmon/stylesheets/monmon.scss
      create  app/assets/stylesheets/units/monmon         # unitsへのシンボリックリンク
      create  app/units/monmon/javascripts/monmon.js
      create  app/assets/javascripts/units/monmon         # unitsへのシンボリックリンク
      create  app/units/monmon/images/logo.png
      create  app/assets/images/units/monmon              # unitsへのシンボリックリンク
* active_ifがtrueならchanko発動
  active_if do |context, options|
    true
  end
    * 複数の定義が全てtrueなら発動(AND)
active_if :staff, :not_production do |context, options|
  # some additional conditions
end
    * 複数の定義のどれかがtrueなら発動(OR)
active_if any(:staff, :not_production)
  1. invokeを呼び出した所でchankoが発動する
# Monmonモジュールのmessage functionが呼び出される
invoke(:monmon, :message)
* 第3引数にhashを渡すことでlocal変数をfunctionに渡すことも可能
invoke(:sample, :show, :if => :depend_on_unit)
* unitを複数作っている場合に配列にして渡すと両方発動できる
invoke([:first_unit, :show], [:second_unit, :show])
* ブロックを渡せばraiseが起きた時はchankoが発動しないときのdefault挙動になる(ここに元の機能を置けばいい)
invoke(:sample, :controller_show) do
   default_behaviour
end

その他

モデルの拡張

  • モデルの拡張もできる(joinやmethodの追加など)
models do
  expand("ExpandedModel") do
     #expanded_model.ext.has_many_associations
     has_many :has_many_associations
     has_one :has_one_association
     has_many :through_associations, :through => label(:has_many_associations)
     named_scope :exists, :conditions => {:deleted_at => nil}
      # expanded_model_instance.ext.new_method
     def new_method
     end

     #expanded_mode.ext.new_method
     class_methods do
      def cmethod
      end
    end
  end
end
* 詳しくは[ChankoのREADME](https://github.com/cookpad/chanko)

参考リンク

  • COOKPAD資料
  • 読み進める
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment