日光のペンションで2泊3日の開発合宿してきました
日光のペンション「はじめのいっぽ」で開発合宿をしてきたのでメモというか感想というか、です。
成果物
- FINAL FANTASY XIV 探検手帳手帳(ネタバレ防止機能付き)
- FF14の探検手帳というコンテンツを攻略するのに便利そうなやつ
- http://lettas.github.io/xiv-tools/apkallu/
- ソースコード: https://github.com/lettas/xiv-tools
- Vue.js + gulp + watchify で開発
- この辺については後日まとめる(たぶん)
- 合宿を盛り上げるHubotスクリプトたち
やってよかったこと
- 前日までに開発環境を準備した
- Javascript素人なのでイマドキの環境わからない
- 開発環境の準備で合宿中の時間の大半を潰した経験がある
- やりたいことに集中する用意はしておくべき
- 合宿で作るものは1から作り始めるのではなく、3くらいから始めるのが良さそう
- 共通のチャットルームにSlackを使った
- スマートフォンアプリがあるので移動中の連絡にも使えた
- 雑談とか、ファイルの受け渡しとか、URLの共有とか
- 大半はHubotで遊んでたけど
そのほか感想など
Railsアプリケーションを公開するならAssets on Cloudパターンを使おう
Assets on Cloudパターンとは
「Assets on Cloudパターン」*1はRailsデザインパターン*2の一つ。Railsアプリケーションの静的なコンテンツ(Assets)をクラウドに配置するパターンである。ファイルサイズの大きい画像などをクラウドに配置することでウェブサーバへのリクエストを減らし、ネットワークリソースを節約する。
Assetsの配置先はAmazon S3を推奨する。
asset_syncの使い方
「Assets on Cloudパターン」はasset_syncというgemを利用する。
Amazon S3の設定方法
asset_syncを設定する前にAmazon S3でバケットを作っておく。バケット名を自分が持ってるドメインのサブドメインと同じにしておくと少しだけ幸せになれる。ドメインを持っていない場合、適当なバケット名でもいいが、全世界で一意にする必要がある。(他の人と同じバケット名でバケットを作成することができないので注意)
また、国内ならRegionをTokyoにしておかないと、ネットワークの速度が遅くなってしまうので注意。
以降はTokyoリージョンに作成したassets.example.comというバケットで説明を進める。
asset_syncの設定方法
Gemfileに以下の記述を追加する。
gem 'asset_sync'
以下の内容でconfig/asset_sync.ymlを用意する。
defaults: &defaults fog_provider: 'AWS' fog_directory: 'assets.example.com' fog_region: 'ap-northeast-1' aws_access_key_id: '<AWSのACCESS KEY>' aws_secret_access_key: '<AWSのSECRET ACCESS KEY>' existing_remote_files: delete manifest: true gzip_compression: true development: <<: *defaults test: <<: *defaults production: <<: *defaults
config/environments/production.rbに以下の記述を追加する。
config.action_controller.asset_host = '//s3-ap-northeast-1.amazonaws.com/assets.example.com'
以上で設定は完了。Assetsのprecompile時に自動的に配置されるようになる。
$ bundle exec rake assets:precompile
capistranoとの連携
capistranoの設定方法
Railsの汎用デプロイツールであるcapistranoと組み合わせることで、アプリケーションのデプロイと同時にAssetsをクラウドに配置することができる。
config/deploy.rbに以下の記述を追加する。
namespace :assets do task :precompile, :roles => :web do run "cd #{current_path} && RAILS_ENV=#{rails_env} bundle exec rake assets:precompile" end task :cleanup, :roles => :web do run "cd #{current_path} && RAILS_ENV=#{rails_env} bundle exec rake assets:clean" end end after :deploy, 'assets:precompile'
はぐれメタルBOTをRuby on Railsに移植しました
はぐれメタルのBOTとそのサイトをRuby on Railsに移植しました。2〜3年前に最初のはぐれメタルができてからほとんど手を加えずに動かしてきたのですが、TwitterのAPIがそろそろ使えなくなりそうなのと、当時の自分のコードなんてメンテナンスする気になれないので、1から作り直しています。
今回の移植で勉強になったことをつらつらと書き連ねます。
Haml
http://haml.info/
もともとのはぐれメタルのサイトはベタ書きの静的なhtmlで構成されていました。それをマルッとHamlに書き直しています。これと言って特別なことはしていません。HamlかわいいよHamlペロペロ。
rails runner
はぐれメタルBOTは定期的に動かすスクリプトなのでRailsには乗せられないかと思ってたんですが、そんなことはなかった。これを使えばRailsに乗ったRubyのコードを簡単に実行できます。
# lib/batches/battle/main.rb module Batches module Battle class Main def self.start # はぐれメタルの処理 end end end end
$ rails runner Batches::Battle::Main.start
本番環境では
$ rails runner -e production Batches::Battle::Main.start
ファイルをどこに置くか迷ったのですが、lib/batches/battle/main.rbに置きました。
便利なGemたち
便利な世の中になったもので、何かしたいと思ったらたいてい誰かが便利なgemを作ってくれています。今回使ったgemの中で特に便利だと思ったものをいくつか挙げます。
tweetstream
https://github.com/intridea/tweetstream
twitterのストリーミングAPIに対応したgem。このgemのおかげではぐれメタルがリアルタイムに応答するようになりました。以下のように使用しています。
EM.run do stream = TweetStream::Client.new EM::Timer.new(180) do stream.stop # 180秒後にストップ end stream.userstream do |status| # はぐれメタルへの攻撃に対する処理 end end
settingslogic
https://github.com/binarylogic/settingslogic
YAMLで定数を管理することができるgem。develop環境とproduction環境で値を変えるなんてこともできます。
こんな感じでtwitterの接続情報をYAMLに書いてます。
# config/twitter.yml development: consumer_key: hogehoge consumer_secret: fugafuga oauth_token: foofoo oauth_token_secret: barbar production: consumer_key: hogehoge consumer_secret: fugafuga oauth_token: foofoo oauth_token_secret: barbar
# lib/settings/twitter.rb module Settings class Twitter < Settingslogic source "#{Rails.root}/config/twitter.yml" namespace Rails.env end end
capistrano
https://github.com/capistrano/capistrano
定番のデプロイツールです。今回使ってみてその簡単さに惚れ惚れしました。
最終的に以下のコマンドでデプロイできるようになりました。プログラムの更新、DBのmigration、assetsのprecompile、unicornの再起動、cronの設定などもろもろが1コマンドで完了です。
$ cap production deploy
whenever
https://github.com/javan/whenever
cronの設定をRubyで書ける優れものです。cronの設定って結構間違えやすいのですが、これなら間違えない設定を書き出してくれます。
# config/schedule.rb set :output, {:error => 'log/error.log', :standard => 'log/cron.log'} every 6.hours do runner 'Batches::Battle::Main.start' end
# crontab -l 0 0,6,12,18 * * * /bin/bash -l -c 'cd /path/to/application && script/rails runner -e development '\''Batches::Battle::Main.start'\'' >> log/cron.log 2>> log/error.log'
asset_sync
https://github.com/rumblelabs/asset_sync
precompileしたassetsをクラウドに配置できるgemです。僕はこれを使ってCSSとJavascriptと画像をAmazonS3に配置しています。静的なファイルを置くならAmazonS3が一番優秀だと思います。
以下の設定ファイルを用意すればassetsのprecompile時に自動的に配置してくれるようになります。
# config/asset_sync.yml production: fog_provider: 'AWS' fog_directory: 'Bucket名' fog_region: 'ap-northeast-1' aws_access_key_id: 'AWSアクセスキー' aws_secret_access_key: 'AWSシークレットアクセスキー' existing_remote_files: delete manifest: true gzip_compression: true
# config/environment/production.rb Hoge::Application.configure do ... config.action_controller.asset_host = '//s3-ap-northeast-1.amazonaws.com/バケット名' end
なんで誰もrails destroyを教えてくれなかったんだ #rails
あけましておめでとうございます。年末年始の休みを利用してRailsで遊んでおります。
そんななか地味に便利なRailsコマンドを見つけたのでメモ。
$ rails destroy
rails generateって便利ですよね。モデルやらコントローラやら何やらかんやらひな形を作ってくれる便利コマンドです。例えばユーザのひな形を作りたいなんていったら以下のコマンドで一発です。
$ rails generate scaffold user name:text age:integer invoke active_record create db/migrate/20130104071427_create_users.rb create app/models/user.rb invoke test_unit create test/unit/user_test.rb create test/fixtures/users.yml invoke resource_route route resources :users invoke scaffold_controller create app/controllers/users_controller.rb invoke erb create app/views/users create app/views/users/index.html.erb create app/views/users/edit.html.erb create app/views/users/show.html.erb create app/views/users/new.html.erb create app/views/users/_form.html.erb invoke test_unit create test/functional/users_controller_test.rb invoke helper create app/helpers/users_helper.rb invoke test_unit create test/unit/helpers/users_helper_test.rb invoke assets invoke coffee create app/assets/javascripts/users.js.coffee invoke scss create app/assets/stylesheets/users.css.scss invoke scss identical app/assets/stylesheets/scaffolds.css.scss
git statusをみると沢山のファイルが増えたことが確認できます。config/routes.rbまで編集してくれてますね。賢い!
$ git status # On branch master # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: config/routes.rb # # Untracked files: # (use "git add <file>..." to include in what will be committed) # # app/assets/javascripts/users.js.coffee # app/assets/stylesheets/users.css.scss # app/controllers/users_controller.rb # app/helpers/users_helper.rb # app/models/user.rb # app/views/users/ # db/migrate/20130104072447_create_users.rb # test/fixtures/users.yml # test/functional/users_controller_test.rb # test/unit/helpers/users_helper_test.rb # test/unit/user_test.rb no changes added to commit (use "git add" and/or "git commit -a")
こんなに沢山のファイルをコマンド1発で作ってくれるとかrails△とか言ってたら間違いに気づく訳ですよ。「あかんnameはtextやなくてstringや」と。
この間違いに気づいたとき、今までの僕はファイルを一つ一つ消していってました。作るのは簡単なのに取り消すのがめんどくさいってどういうことやねん。
ところが、これらのファイルをコマンド1発で消してくれるコマンドがあったんです。マジ、rails△。以下のコマンドで1発です。
$ rails destroy scaffold user invoke active_record remove db/migrate/20130104071427_create_users.rb remove app/models/user.rb invoke test_unit remove test/unit/user_test.rb remove test/fixtures/users.yml invoke resource_route route resources :users invoke scaffold_controller remove app/controllers/users_controller.rb invoke erb remove app/views/users remove app/views/users/index.html.erb remove app/views/users/edit.html.erb remove app/views/users/show.html.erb remove app/views/users/new.html.erb remove app/views/users/_form.html.erb invoke test_unit remove test/functional/users_controller_test.rb invoke helper remove app/helpers/users_helper.rb invoke test_unit remove test/unit/helpers/users_helper_test.rb invoke assets invoke coffee remove app/assets/javascripts/users.js.coffee invoke scss remove app/assets/stylesheets/users.css.scss invoke scss
めっちゃ消えた!git statusをみるとちゃんとconfig/routes.rbも元通りです。
$ git status # On branch master nothing to commit, working directory clean
うむ。すっきり。
まとめ
generateしたものをdestroyする準備はできているからこれからも怖がらずにgenerateしまくろうね!ってことで。
Rails3のルーティングについて自分なりにまとめてみる #rails
最近Rails3で遊んでて、ようやくルーティングが分かってきたのでまとめます。僕の知ってる範囲しかまとめないので、すべての機能を網羅するわけではありませんが、これだけ知ってれば不自由しない気がするのでそれで良いです。ウフフ、オッケー。
基本的なこと
Railsの思想
Railsのルーティングを理解するのに、押さえておくべき思想は一つかなと思います。
「すべての操作はリソースに対するCRUD操作である」
これを念頭においておくと、ルーティングの理解がしやすくなると思います。
編集するファイル
ルーティングは以下のファイルに記述します。基本的にこれだけを見れば全部のルーティングがわかるようになっています。
config/routes.rb
resources
引数に与えた名前のリソースに対するCRUD操作を行う為のルートを定義します。
resources :posts
これを rake routes で確認すると以下のようになります。
$ rake routes posts GET /posts(.:format) posts#index POST /posts(.:format) posts#create new_post GET /posts/new(.:format) posts#new edit_post GET /posts/:id/edit(.:format) posts#edit post GET /posts/:id(.:format) posts#show PUT /posts/:id(.:format) posts#update DELETE /posts/:id(.:format) posts#destroy
各アクションの役割
各アクションの役割は以下のとおりです。
アクション | 役割 | viewを持つか | CRUD | おもな遷移先 |
---|---|---|---|---|
posts#index | postの一覧を表示する | o | R | show,new,destroy |
posts#create | postを新規作成する | x | C | show |
posts#new | postを新規作成するための情報を入力する | o | R(C) | create |
posts#edit | postを更新するための情報を入力する | o | R(U) | update |
posts#show | postの詳細な情報を表示する | o | R | edit |
posts#update | postを更新する | x | U | show |
posts#destroy | postを削除する | x | D | index |
アクションを限定することができる
新規作成はできるけど更新はできないとか、削除させないとかを制御することができます。
:onlyを使うことで、指定したアクションだけのルートを定義することができます。
resources :posts, :only => [:new, :create]
$ rake routes posts POST /posts(.:format) posts#create new_post GET /posts/new(.:format) posts#new
:exceptを使うことで、指定したアクション以外のルートを定義することができます。
resources :posts, :except => [:edit, :update, :destroy]
$ rake routes posts GET /posts(.:format) posts#index POST /posts(.:format) posts#create new_post GET /posts/new(.:format) posts#new post GET /posts/:id(.:format) posts#show
意図に合わせて適宜使い分けると良いでしょう。
resourcesのネスト
resourcesをネストさせることもできます。
resources :posts do resources :comments end
$ rake routes post_comments GET /posts/:post_id/comments(.:format) comments#index POST /posts/:post_id/comments(.:format) comments#create new_post_comment GET /posts/:post_id/comments/new(.:format) comments#new edit_post_comment GET /posts/:post_id/comments/:id/edit(.:format) comments#edit post_comment GET /posts/:post_id/comments/:id(.:format) comments#show PUT /posts/:post_id/comments/:id(.:format) comments#update DELETE /posts/:post_id/comments/:id(.:format) comments#destroy posts GET /posts(.:format) posts#index POST /posts(.:format) posts#create new_post GET /posts/new(.:format) posts#new edit_post GET /posts/:id/edit(.:format) posts#edit post GET /posts/:id(.:format) posts#show PUT /posts/:id(.:format) posts#update DELETE /posts/:id(.:format) posts#destroy
commentsに対するルーティングが定義されました。パスの先頭に /posts/:post_id がつきます。
namespace
管理画面を作りたいときなんかに便利なのがnamespaceです。例を見ましょう。
namespace :admin do resources :users end
$ rake routes admin_users GET /admin/users(.:format) admin/users#index POST /admin/users(.:format) admin/users#create new_admin_user GET /admin/users/new(.:format) admin/users#new edit_admin_user GET /admin/users/:id/edit(.:format) admin/users#edit admin_user GET /admin/users/:id(.:format) admin/users#show PUT /admin/users/:id(.:format) admin/users#update DELETE /admin/users/:id(.:format) admin/users#destroy
パスの先頭に /admin がつくようになります。注意事項が2点あります。
- model, view, controller の各ファイルを(基本的に)adminディレクトリ以下に配置する必要がある
- model, controller のクラスを(基本的に)Adminモジュールの内部に宣言する必要がある
MVC | ファイル | クラス |
---|---|---|
model | app/models/admin/user.rb | Admin::User |
view | app/views/admin/〜 | なし |
controller | app/controllers/admin/users_controller.rb | Admin::UsersController |
root
ルート(/)へのルーティングを定義します。
root :to => 'posts#index'
$ rake routes root / posts#index
namespaceの下に定義することもできます。
root :to => 'posts#index' namespace :admin do root :to => 'users#index' end
$ rake routes root / posts#index admin_root /admin(.:format) admin/user#index
match
matchを使うと、比較的自由にルーティングを定義することができます。例えばomniauth等のプラグインを使って外部サービス経由でのログインをする場合、以下のように設定することになると思います。
match '/auth/:provider/callback' => 'sessions#create'
$ rake routes /auth/:provider/callback(.:format) sessions#create
まとめ
Rails3のルーティングについて僕が知ってることは以上です。間違ってたりしてたら指摘してもらえると嬉しいです。もっと高度な設定を教えてくれる人も大歓迎です。
「すべての操作はリソースに対するCRUD操作である」
とにかく、このことだけ忘れなければ色々すっきりすると思っています。
ApacheのHttpClient 4でPOSTメソッドでも自動的にリダイレクトする方法メモ
HttpClient 4ってPOSTリクエストの時に相手のサーバが302を返してきても自動的にリダイレクトしてくれないんです。
自分でリダイレクトするしかないかなーって思ってたところにいい方法を見つけたのでメモします。
DefaultHttpClient client = new DefaultHttpClient(); client.setRedirectStrategy(new DefaultRedirectStrategy() { @Override public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException { boolean isRedirected = super.isRedirected(request, response, context); if (!isRedirected) { int statusCode = response.getStatusLine().getStatusCode(); if (statusCode == 301 || statusCode == 302) { return true; } } return isRedirected; } });
HttpClientのインスタンスにRedirectStrategyを追加するだけっていう簡単なお仕事です。
PHPのstrtotime関数で +1 month するときの注意
PHPのstrtotime関数で来月、再来月のmonthを取得してたらハマったのでメモ。実際ハマったのは+2 monthの時だけど、月によっては+1 monthでハマれると思う。
今日(2012/07/31)の時点で以下のコードを実行すると '2012-10' と表示されます。本当は '2012-09' であって欲しかった・・・。
<?php // 今日から2ヶ月後のtimestampが欲しいよー $timestamp = strtotime('+2 month', date()); $yyyymm = date('Y-m', $timestamp); var_dump($yyyymm);
解決策は以下。 '2012-07-01+2 month' になるようにすればいいらしい。
<?php $timestamp = strtotime(date('Y-m-01').'+2 month'); $yyyymm = date('Y-m', $timestamp); var_dump($yyyymm);
あ、dayまで求めたい時は '2012-10-01' になるのが正解なのか。