ActiveRecordのマイグレーションでMySQLのunsignedな数値タイプを指定できるGemライブラリ作った
今の会社でRailsを使うようになって、いわゆるマイグレーションの仕組み超便利。
なんですが、MySQLを使っているのにidや数値にunsignedを指定できないのどうなんだろう。
他のDBはサポートしてないからいらないよねっていうのも分かるんですが、せっかくアダプタが分けられてるならサポートしてもいいんじゃないかな。
ということで、ActiveRecordの勉強がてらマイグレーションでintegerなカラムに"unsigned"を指定できるGemライブラリを作ってみました。
github/activerecord-mysql-unsigned
ついでに初めてのRubyGemsで公開もしてみた。
rubygems/activerecord-mysql-unsigned
ActiveRecord3.2以降と4で動作確認しています。
使い方はGemfileに書いて、マイグレーションファイルで「unsigned: true」をオプションに指定するだけ。
class CreateUsersTable < ActiveRecord::Migration def self.change create_table :users, force: true do |t| t.string :name, null: false t.integer :age, null: false, unsigned: true end end end
既存のテーブルの主キーや数値カラムを置き換えるのが主目的なので、change_columnでも使えます。
このためにv3.2でauto_incrementをオプションで指定できるようにもしてあったり。
class ChangeColumnToUsersTable < ActiveRecord::Migration def self.change change_column :users, :id, :integer, null: false, unsigned: true, auto_increment: true # 主キー change_column :users, :age, :integer, null: false, unsigned: false end end
v3.2とv4.0の両方対応させるためにActiveRecordのソース読みましたが、中のクラス構造や挙動が結構変わってるんですねー。
v3.2だとunsignedな数値カラムにマイナス値を入れると0が保存される。v4.0だとActiveRecord::StatementInvalidエラーにしてくれる。
v4.0の方が圧倒的に見通しもいいしソースも綺麗。カラムのマイグレーションにもcollationやextraオプションを指定できたりいろいろ便利そうな機能を発見しました。
ウチのサービスも早く4.0にしたいなーっ。。。
WEB+DB PRESS Vol.76にWeb Componentsの記事を書きました
うう、発売されてからだいぶ経ってしまった。。。
WEB+DB PRESSのJavaScript連載の第9回目にWeb Componentsについての記事を書かせていただきました。
- 作者: 五十嵐啓人,伊野亘輝,近藤宇智朗,渡邊恵太,須藤耕平,中島聡,A-Listers,はまちや2,川添貴生,片山育美,池田拓司,濱崎健吾,佐藤太一,曾川景介,久保渓,門脇恒平,登尾徳誠,伊藤直也,mala,後藤秀宣,若原祥正,奥野幹也,大林源,WEB+DB PRESS編集部
- 出版社/メーカー: 技術評論社
- 発売日: 2013/08/24
- メディア: 大型本
- この商品を含むブログを見る
サービス/アプリの作り始めは特に気にする必要もないのですが(最初から検討するリソースがあるならその方がいいけど)、ページ数の多いサイト、インタラクションの多いアプリなどを作っていると、何かしらの方法でクライアントサイドのコンポーネント化を考えますよね。
サーバサイドのビューライブラリでのHTMLテンプレート化、Sassなどのmix-in、RequireJSなどを使って依存関係解決など、HTML/CSS/JavaScriptを個別にコンポーネント化していったり。
そうやってコンポーネント化が進んでくると、HTML/CSS/JavaScriptトータルで見たときの管理コストが逆に増えるケースもあると思います。
このJSであてられてるCSSクラスはどこで定義されてるんだろうとか、どの画面のどのDOMにこのJSコンポーネントは適用されているのか、とか。
大きめのクライアントサイドアプリだと、後から入ってくる人はHTMLの構造を把握するのも結構大変ですよね。
jQueryUIなんかそうですけど、UIコンポーネントを適用するために決まったDOM構造をHTMLに定義しておかないとよく分からないセレクタエラーで動いてくれない。ドキュメント通りのHTML構造にしろ、とかそういうHTMLの枠組みはUIコンポーネントの責務なのでは、、と思うこともしばしば。
そういった不便をブラウザネイティブの機能として解消してくれそうなのがWeb Componentsだと思っています。 なんせカスタムタグ一発でビデオタグみたいなリッチなUIを提供できるわけなので、ライブラリを使う人からしたらとても楽チン。
まだまだ一部の仕様しか使えないWeb Conponentsですが、GoogleのPolymerに続きMozillaもBrickを公開してきたりと、動きが活発になってきて楽しい感じです。
実際にvideoタグやaudioタグなどは既にブラウザに実装されて普通に使われているわけなので、運用も問題なさそう。 ただ、実際に普及するにはIEが実装してくれないとですが><
Nginx1.3でWebsocketをリバースプロキシするメモ
Nginx1.3(2013/04/10時点では開発版)からWebsocketのリバースプロキシを通せるようになったということで、Socket.IOへリバースプロキシさせようとしたけどけどなかなか上手くいかなくて、ようやく上手く動いたのでメモっておく。
Nginxのバージョンは1.3.14です。
http { upstream socketio { server localhost:3000; } server { listen 80; charset UTF-8; server_name _; # all accept location /socket.io { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Nginx-Proxy true; proxy_pass http://socketio; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } } }
"upgrade"は小文字でないとダメ。ここを最初"Upgrade"にしててハマったという。。
RailsアプリのJavaScriptをkonachaを使ってCLI上でテストする
前回のでアプリケーションのテストがMiniTest::Specで実行できるようになったので、今度はJavaScriptのユニットテストをコマンドラインから実行できるようにする。
慣れてるMochaを使ってテストが書けるkonachaと、konachaが使用するCapybaraのPhantomJSドライバであるpoltergeistを使う。
Gemfile
group :test do gem 'konacha' gem 'poltergeist' end
konachaの設定はinitializerで。
ドライバをpoltergeistにして、テスト対象ディレクトリを"test/javascripts"に変えた(デフォルトは"spec/javascripts")。
config/initializers/konacha.rb
if defined?(Konacha) Konacha.configure do |config| require 'capybara/poltergeist' config.driver = :poltergeist config.spec_dir = "test/javascripts" end end
mochaの設定はテストディレクトリ直下にspec_helper.jsを置いてその中に書くらしい。
test/javascripts/spec_helper.js
// set the Mocha test interface // see http://visionmedia.github.com/mocha/#interfaces mocha.ui('bdd'); // ignore the following globals during leak detection mocha.globals(['util']); // or, ignore all leaks mocha.ignoreLeaks(); // set slow test timeout in ms mocha.timeout(5);
テストディレクトリ以下にある、"hoge_test.js"あるいは"hoge_spec.js"というファイルがテストファイルとなる。
もちろんSprokectsを使ってRailsのasset pipelineを使ってテストしたいJSファイルを読み込むことができる。
precompile済みならapplication.jsを指定するくらいか。
//= require spec_helper //= require application
あとはchaiのアサーションを使ってテストを書いてkonacha:runすればphantomjsでテストが実行される!
RAILS_ENV=test bundle exec rake konacha:run
Rails4で書いたアプリをMiniTest::Specでテストする
Rails4からはActiveSupport::TestCaseがTest::UnitからMiniTest::Unit::TestCaseのサブクラスに変わっている。
MiniTestはSpecなDSLをサポートしているので、RSpecを入れずともBDDスタイルでテストが書けるようになる。
ということで、いろいろtest_helper.rbをゴニョってたらminitest-rails-specというズバリなGemを見つけたので(><)これを使う。
minitest-spec-railsでやってくれることは、ざっくりいうと、RailsのActiveSupport::TestCaseにMinitest::Spec::DSLをextendして、ControllerとかHelperクラスをテスト対象クラスに追加して、beforeとかafterとかのDSLを使えるようにしてくれるだけというシンプルな作りになっている。
使えるDSLはチートシートにまとめてくれている人がいるけど、ソースコメントにも使い方が書いてあるので数も多くないしRDocか直接のぞいて見てみるのがよさげ。
environments/test.rbなどに以下を書くと、context(describeのエイリアス)やshould(itのエイリアス)も使えるようになる。
config.minitest_spec_rails.mini_shoulda = true
Gemfile
gem 'rails', '4.0.0.beta1' group :test do gem 'minitest-spec-rails' gem 'factory_girl_rails' end
Factoryはこんな感じで定義しておく
FactoryGirl.define :tester1, class: User do name "tester1" password "tester1tester1" email "tester1@example.com" end
まずは普通にモデルをテスト
test/models/user_test.rb
require 'test_helper' describe User do context '#attributes' do it '#name is required' do tester1 = Factory.create :tester1 proc = Proc.new do tester1.update(name: "") end proc.must_raise ActiveRecord::RecordInvalid end end end
$ bundle exec rake test:models Run options: --seed 30682 # Running tests: . Finished tests in 1.190526s, 6.1302 tests/s, 3.2388 assertions/s. 1 tests, 1 assertions, 0 failures, 0 errors, 0 skips
よさそう。 続いてAPIコントローラのテスト。 登録ユーザーの一覧をJSONで返すAPIが「Api::UsersController」クラスのindexメソッドに定義されているのでテストする。
test/controllers/api/users_controller_test.rb
require 'test_helper' # describeメソッドにテストするコントローラクラスをセットすることで、テストメソッド内で"get :index"など書くと、 # ActionController::TestRequestリクエストを作って、 # コントローラのアクションを実行して、 # 結果をActionController::TestResponseで判定できる describe Api::UsersController do before { 20.times do |idx| User.create( name: "user#{idx}", password: "user#{idx}password", email: "user#{idx}@example.com" ) end } it "#GET /api/users - とりあえず全件返す" do get :index res = JSON.parse(response.body) res["users"].size.must_equal 20 end end
ログインしないと叩けないAPIはテスト用にログインメソッド作ってやると書きやすい気がする。
test_helper.rbに追加
class ActionController::TestCase include ApplicationHelper def start_session_test(user_id) @controller.reset_session @controller.session[:login_id] = user_id end end
これをリクエストを発行する前に実行すればいい
require 'test_helper' describe Api::UsersController do before { @tester1 = Factory.create :tester1 } it "#GET /api/my - ログインユーザー情報を返す" do start_session_test @tester1.id # tester1でログイン get :my res = JSON.parse(response.body) res["user"]["name"].must_equal "tester1" end end