IMG_5313
Releases

新音楽サービスStaart(スターート)をリリースしました!

ハレノヒから新しい音楽サービスStaart(スターート)をリリースしました。

Staartは日本全国のライブ・イベント情報をあつめて、ジャンルや位置情報に応じて次々とおすすめのライブ・イベント情報を紹介してくれるサービスです。

サイトは自由に見られますが、ユーザー機能はまだ公開していません。
しかし一日も早く皆さんに使っていただきたいので目下開発中です。

ユーザー機能のリリース時にすぐご利用していただけるように招待希望の方専用のメールアドレス登録フォームがトップページに用意してあります。

是非Staartを御覧ください!そしてライブをみつけて見に行こう!

ライブ・イベント情報ナビStaart(スターート)

IMG_6953

IMG_5313

標準
ruby-on-rails
Development

[Rails] モデルのデフォルト値セットをService Objectにしてみた

RailsのようなMVCアーキテクチャのフレームワークではControllerに処理を書くことを極力避けることでFat Controllerにならないようにするのはもう常識と言えるまでに浸透してますよね。

しかし最近はModelに何でもかんでも詰め込みすぎてFat Modelにならないようにしようという動きも有ります。
僕は最初、あぁそれでConcernに分けていくのねと思ったのですがConcernだけでかたづく問題ばかりではありません。

詳しくは
ここ 7 Patterns to Refactor Fat ActiveRecord Models
またはここあたり Object Oriented Rails – Writing better controllers
を読むのがいいようですが、そのなかにService Objectというのがあります。

今回そのService Obejctでモデルのデフォルト値をセットする処理を書いてみましたので紹介します。

まずTask管理をするRailsアプリがあったとしますTasksController#newでこんなコードになってました。

class TasksController
  def new
    @task = Task.new
    @task.category = category if params[:category_name].present? && (category = Category.find_by_name(params[:cateogry_name]).present?
    @task.due_date = params[:due_date].present? ? params[:due_date] : Date.tomorrow
  end
end

ごちゃごちゃしていて分かりづらいですね。

いきなり結果ですが、前述のブログを参考に以下のように変えてみました

class TasksController
  before_action :load_task_default_value_service, only: [:new]

  def new
    @task = Task.new
  @task = @task_default_value_service.set(@task, params)
  end

  private
    def load_task_default_value_service(service = TaskDefaultValueService.new)
      @task_default_value_service ||= service
    end
end

大分スッキリしました。

で肝心のService Obejctは app/services ディレクトリを作って配置します。このとき config/application.rb で config.autoload_path に app/services を追加しておかなければいけません。

app/services/task_default_value_service.rb

class TaskDefaultValueService
  def set(task, params)
    @params = params
    task.category = @cateogry if valid_category_name?
    task.due_date = due_date
  end

  def valid_category_name?
    @category = Category.find_by_name(params[:cateogry_name])
    @params[:category_name].present? && @category.present?
  end

  def due_date
    @params[:due_date].present? ? @params[:due_date] : Date.today
  end
end

たったこれだけの処理が専用のクラスに切り分けることでかなり読みやすくなりますね。

ここまでやって気になったんですがControllerからService Objectを呼び出しておく部分って冗長になりそうだなとおもったんです。
例えば今回だと before_action で load_task_default_value_service を実行するようにしてますが、これってService Objectの名称が変わるだけで同じ処理をたくさん書くはめになりそうです。

なので ApplicationController で method_missing を使ってService Objectの呼び出しを簡単に出来るようにしてみました。

class ApplicationController
  def method_missing(method_name, *arg)
    if method_name =~ /^load_([a-z_]+)_service$/
      load_service_object($1)
    else
      super
    end
  end

  private
    def load_service_object(service_name)
      service_snakecase = (service_name + '_service')
      service = service_snakecase.camelize.constantize
      instance_variable_set("@#{ service_snakecase }", service.new)
    end
end

こうしておけば UserAuthenticationService を使いたい時は

  before_action :load_user_authentication_service

と書くだけでいいので簡単ですね!

標準
php-logo-a855de85906d6219bb3f642cddf45168
Development

herokuで公式サポートになったPHPを試してみた

herokuでPHPの公式サポートが発表されましたね。

Introducing the new PHP on Heroku

以前からbuild packを使用すればPHPを動かすことは出来ましたが公式となると面倒な手順なしに動くので便利そうな感じです。

Hello Worldしてみる

まずはハロワしてみます
用意するのは以下のものです。

  • index.php
  • composer.json(空でOK)
  • 上記が含まれたgitリポジトリ
$ heroku create
Creating frozen-beach-1321... done, stack is cedar
http://frozen-beach-1321.herokuapp.com/ | git@heroku.com:frozen-beach-1321.git
Git remote heroku added
$ git push heroku master
Initializing repository, done.
Counting objects: 4, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (4/4), 293 bytes | 0 bytes/s, done.
Total 4 (delta 0), reused 0 (delta 0)

-----> PHP app detected

       NOTICE: Your composer.json is completely empty.
       Consider putting at least "{}" in there to make it valid JSON.
       See https://devcenter.heroku.com/categories/php

-----> Setting up runtime environment...
       - PHP 5.5.11
       - Apache 2.4.9
       - Nginx 1.4.6
-----> Installing PHP extensions:
       - opcache (automatic; bundled, using 'ext-opcache.ini')
-----> Building runtime environment...
       NOTICE: No Procfile, defaulting to 'web: vendor/bin/heroku-php-apache2'
-----> Discovering process types
       Procfile declares types -> web

-----> Compressing... done, 60.7MB
-----> Launching... done, v3
       http://frozen-beach-1321.herokuapp.com/ deployed to Heroku

To git@heroku.com:frozen-beach-1321.git
 * [new branch]      master -> master
$ heroku open
Opening frozen-beach-1321... done

簡単すぎる…

しかも日本語もバッチリでした!

composerでライブラリを動かしてみる

composerもかなり便利そうなのは知ってたんですが使ったことなかったのでこの機会に始めてみようと思います。
まずはcomposerのインストールですが、以下のコマンドで良いようです

 curl -sS https://getcomposer.org/installer | php

これで実行したディレクトリに composer.phar がダウンロードされました。
このファイルは gitignore しておいたほうがいいみたいですね。

とりあえず最近のPHPよくわからないしSinatraみたいな軽量フレームワークでもインストールしてみようと検索したら、Silexというのがなんとなく良さげな感じだったのでこれを試してみることにしました。

composer.json

{
  "require": {
    "silex/silex": "2.0.*@dev"
  }
}
$ ./composer.phar install
Loading composer repositories with package information
Installing dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Installation request for silex/silex 2.0.*@dev -> satisfiable by silex/silex[2.0.x-dev].
    - silex/silex 2.0.x-dev requires pimple/pimple ~2.1@dev -> no matching package found.

Potential causes:
 - A typo in the package name
 - The package is not available in a stable-enough version according to your minimum-stability setting
   see  for more details.

Read  for further common problems.

おっとダメでした。なんだろなこれ、とりあえずバージョンを1つ落として再チャレンジしてみます。

composer.json

{
  "require": {
    "silex/silex": "1.2.*@dev"
  }
}
$ ./composer.phar install
Loading composer repositories with package information
Installing dependencies (including require-dev)
  - Installing symfony/routing (v2.4.4)
    Downloading: 100%

  - Installing psr/log (1.0.0)
    Downloading: 100%

  - Installing symfony/debug (v2.4.4)
    Downloading: 100%

  - Installing symfony/http-foundation (v2.4.4)
    Downloading: 100%

  - Installing symfony/event-dispatcher (v2.4.4)
    Downloading: 100%

  - Installing symfony/http-kernel (v2.4.4)
    Downloading: 100%

  - Installing pimple/pimple (v1.1.1)
    Downloading: 100%

  - Installing silex/silex (1.2.x-dev 6d9e3fe)
    Cloning 6d9e3fe4d7d9ed563800ee8b4559bd51c13457e5

symfony/routing suggests installing symfony/config (For using the all-in-one router or any loader)
symfony/routing suggests installing symfony/yaml (For using the YAML loader)
symfony/routing suggests installing symfony/expression-language (For using expression matching)
symfony/routing suggests installing doctrine/annotations (For using the annotation loader)
symfony/event-dispatcher suggests installing symfony/dependency-injection ()
symfony/http-kernel suggests installing symfony/browser-kit ()
symfony/http-kernel suggests installing symfony/class-loader ()
symfony/http-kernel suggests installing symfony/config ()
symfony/http-kernel suggests installing symfony/console ()
symfony/http-kernel suggests installing symfony/dependency-injection ()
symfony/http-kernel suggests installing symfony/finder ()
silex/silex suggests installing symfony/browser-kit (>=2.3,<2.6-dev)
silex/silex suggests installing symfony/css-selector (>=2.3,<2.6-dev)
silex/silex suggests installing symfony/dom-crawler (>=2.3,<2.6-dev)
silex/silex suggests installing symfony/form (>=2.3,<2.6-dev)
Writing lock file
Generating autoload files

今度は成功しました。
composerの出力、bundlerより見やすいし親切だしいいですねこれ。

Silexのコードはこちらを参考に(というか丸パクリ)させていただきました。
PHP - SilexでHello World - Qiita

<?php
require_once __DIR__.'/vendor/autoload.php';

$app = new Silex\Application();

$app->get('/', function() {
    return "Hello World!";
});

$app->get('/hello/{name}', function($name) use($app) {
    return 'Hello '.$app->escape($name);
});

$app->run();

でPHP5.4からのビルトインサーバーを初起動!

php -S 0.0.0.0:8080
PHP 5.4.16 Development Server started at Fri May  2 22:02:16 2014
Listening on http://0.0.0.0:8080
Document root is /Users/kozo/tmp/heroku_php_kozo
Press Ctrl-C to quit.

すげー動いた!っていつもrubyでやってることとそんなに変わらないんだけど、PHPでこれが出来るのは結構感動しますね。

で、Silexでハロワ確認出来たのでこのまま、herokuにプッシュしてみます。

$ git add .
$ git commit -m "Install Silex"
[master 77d66b2] Install Silex
 3 files changed, 523 insertions(+), 2 deletions(-)
 create mode 100644 composer.lock
$ git push heroku master

heroku上ではトップページは動作したんですが、他のルーティングがNot Foundになってしまいました。
これはhtaccessでrewriteすればいいのかな?と思ったので以下の様な内容で作成してコミットしたら動きました!

<IfModule mod_rewrite.c>
 RewriteEngine On
 RewriteBase /
 RewriteRule ^index\.php$ - [L]
 RewriteCond %{REQUEST_FILENAME} !-f
 RewriteCond %{REQUEST_FILENAME} !-d
 RewriteRule . /index.php [L]
</IfModule>

いやーherokuでこんなにも簡単にPHPが動くともっとPHP使いたくなっちゃいますねー。

標準