acts_as_paranoid + ユニークインデックス
Railsで論理削除を行うときはacts_as_paranoidを使用するのが一般的です。
Model側でvalidates_uniqueness_of_without_deletedを使用するとユニーク制限をかけることができますが、DB側でユニーク制限をかけようとすると問題が発生します。
# schema.rb create_table "customers", :force => true do |t| t.string "code", :null => false t.datetime "deleted_at" t.datetime "created_at" t.datetime "updated_at" end add_index "customers", ["code", "deleted_at"], :name => "customers_idx01", :unique => true
一見正しそうですがnullはユニーク制限の対象外となり次のようなレコードが入ってしまいます。
|code|deleted_at| |001| NULL| |001| NULL|
こういう時はindexにwhere条件を指定して直接DBに設定しましょう。
class AddIndexCodeToCustomers < ActiveRecord::Migration def self.up sql = 'create unique index customers_idx01 on customers (code) where deleted_at is null;' ActiveRecord::Base.connection.execute(sql) end def self.down remove_index :customers, :name => :customers_idx01 end end
procedureを使用してDBの操作を行うとRailsのModelを経由しないのでバリデーションが行われません。そういった場合はDB側でもチェックを行いたいですね。
CoffeeScriptオンリーでWebアプリを作ってみた
この記事は大都会岡山 Advent Calendar 2012向けに書いたものです。
昨日の@ore_publicさんの記事は読みましたか!?さすが僕らのリーダーやで。
さて私、RailsからRubyを始めたワリにはCSSとかJavaScriptとか苦手で、あまり関わらないように生きてきました。しかし、CoffeeScriptの登場で大量のfunctionや"{}"や";"を使わずともJavaScriptを書くことができる時代になりました。ステキ。せっかく時代がこちらへ歩み寄ってきてるのだから、なにか作ってみることにしました。
お題はLuckOfWiseさんが会社の飲み会用に作ってたAndroidアプリを真似てみることに。車輪の再発明はムダじゃない!モチベーションが大切です。
できた。
http://tomikuji.herokuapp.comで使うことができます。ソースはgithubに置いてます。
オータムジャンボ宝くじの番号を入力すると当たりの可能性が表示されます。会社で共同購入したくじをみんなで開封するときに使うと楽しいです。
Rails
普通にRails new tomikujiして空のcontrollerを作っただけです。今回は動作確認やCoffeeScriptをコンパイルするのがRailsの役目です。
コントローラとビューはこんな感じ
├── controllers │ ├── application_controller.rb │ └── main_controller.rb └── views ├── layouts │ └── application.html.erb └── main └── index.html.erb
CoffeeScript
前方一致で当たりの可能性を表示するロジックはちょっと工夫してみました。
# Place all the behaviors and hooks related to the matching controller here. # All this logic will automatically be available in application.js. # You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ $(document).ready -> if Modernizr.touch $(".key").bind 'touchend', (event) -> btnClick($(@).text()) else $(".key").click -> btnClick($(@).text()) setTimeout("scrollTo(0,1)",100) # 当たり番号 hits = "1等" : "187077" "2等" : "179409" "3等" : "119658" "4等" : "....30" "5等" : ".....9" # 表示処理 btnClick = (number) -> if number == "clear" $("#number").text("") $("#message").text("") else score = $("#number").text() + number if score.length <= 6 $("#number").text(score) showResult(score) # 結果表示 showResult = (score) -> message = "" for key, value of hits diff = value.slice(0, score.length) if score.match(new RegExp("^#{diff}")) message = message + key if message == "" $("#message").text("残念!") else $("#message").text("#{message}の可能性があります")
初めはスマートフォン用もclickイベントを使ってたんですが、処理速度がメチャクチャ遅かったんですよね。なので、touchイベントに変えました。clickイベントを使うかtouchイベントを使うかの判断はModernizrを使ってみました。
css
普通のブラウザ用とスマホ用の2つを用意して画面の幅によって切り替えてみました。レスポンシブデザインとかやってみたかったの。
<head> <title>富くじ</title> <link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.9.0/build/base/base-min.css"> <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0" /> <%= stylesheet_link_tag "application", :media => "screen and (min-width: 641px)" %> <%= stylesheet_link_tag "application_small", :media => "screen and (max-width: 640px)" %> <%= javascript_include_tag "application" %> <%= javascript_include_tag "http://modernizr.com/downloads/modernizr.js" %> <%= csrf_meta_tags %> </head>
通常は複数のscssファイルが1つに統合されてしまうのですがマニフェストファイルを編集して2つに分けています。
stylesheets/ ├── application.css ├── application_small.css ├── main.css.scss └── small.css.scss
app/assets/stylesheets/application.cssにmain.css.scssを読み込むように設定
/* * This is a manifest file that'll be compiled into application.css, which will include all the files * listed below. * * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. * * You're free to add application-wide styles to this file and they'll appear at the top of the * compiled file, but it's generally better to create a new file per style scope. * *= require_self *= require main.css.scss */
app/assets/stylesheets/application_small.cssにsmall.css.scssを読み込むように設定
/* * This is a manifest file that'll be compiled into application.css, which will include all the files * listed below. * * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. * * You're free to add application-wide styles to this file and they'll appear at the top of the * compiled file, but it's generally better to create a new file per style scope. * *= require_self *= require small.css.scss */
あとはconfig/environments/production.rbに明示的にプリコンパイルするcssファイルを記述します。
# Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) config.assets.precompile += %w( application_small.css )
こんな感じでCoffeeScriptを使ってWebアプリを作ることができました。ちょっとしたアプリならクライアントだけで実現できるのがいいですね。
さて、明日はハカセのアイコンでお馴染みのにゃーさんです。お楽しみに!
Java Preferencesが消えた世界でいかにしてJavaのバージョンを切り替えるか
(2012.11.20 追記)
aoetkさんからコメントでご指摘いただきました。Javaコントロールパネルからpathをコピーする方法はApple的に推奨されていないようです。
http://developer.apple.com/library/mac/#qa/qa1170/_index.html
/usr/libexec/java_homeコマンドがpathを返すようなので、その実行結果をJAVA_HOMEに設定します。
.bash_profileか.bashrcにJAVA_HOMEを設定
export JAVA_HOME=`/usr/libexec/java_home` export JAVA=$JAVA_HOME/bin
↓↓↓ここから元記事↓↓↓
いつの間にやらMacOS XからJava Preferencesが消失してしまいました。
Java言語で開発を行うことはないのですがJenkinsはできれば1.7系で動かしたいのです。
さてどうやって切り替えようかと思っていたのですが会社でpatorashさんが良い方法を教えてくれました。
.bash_profileか.bashrcにJAVA_HOMEを設定
JAVA_HOMEはさっきコピーした内容をそのままペーストするのではなく、最後の/bin/javaは取り除きます。
例えば次のような内容であれば
/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java
次のようになります。
export JAVA_HOME="/Library/Internet Plug-ins/JavaAppletPlugin.plugin/Contents/Home" export JAVA=$JAVA_HOME/bin
切り替わったか試してみましょう。
$ source .bash_profile $ java -version java version "1.7.0_09" Java(TM) SE Runtime Environment (build 1.7.0_09-b05) Java HotSpot(TM) 64-Bit Server VM (build 23.5-b02, mixed mode)
OK!良い感じです。
rbenv rehashを行わなくて良い方法
rvmがオワコン扱いされだしたのはいつの頃からでしょうか?私はrbenvのrehashが嫌でしつこくrvmを使い続けていたのですが、ここ最近のrvmでのrubyインストールの不安定さに嫌気が差してrbenvに乗り換えることにしました。
$ cd $ rm -rf .rvm $ brew install rbenv$ brew install ruby-build $ echo 'eval "$(rbenv init -)"' >> .bash_profile $ brew install readline $ rbenv install 1.9.3-p194 $ rbenv global 1.9.3-p194
ちょとirbで動作確認してみます。
a = 1 a = 2 # ↑キーを押してキーヒストリが効くことを確認。readlineがうまく組み込まれてないとヒストリが効かない require 'psych' #yamlパーサーの確認。rvmはここで詰まることがよくある require 'zlib' #同じくrvmはここで詰まることがよくある require 'openssl' #同じく(略)
私の環境では問題ありませんでした。
次にrbenv で gem を使った時に rbenv rehash しなくて良くするというエントリを参考にしてシェルスクリプトで関数定義を行い、gemおよびbundleコマンドのオーバーライドを行いました。私のPCはMacOS Xなんですがrehashコマンドは無いみたいなので参考元のスクリプトからコピーする際に省いています。
$ vi .bash_profile
#適当な場所に定義 function gem(){ $HOME/.rbenv/shims/gem $* if [ "$1" = "install" ] || [ "$1" = "i" ] || [ "$1" = "uninstall" ] || [ "$1" = "uni" ] then rbenv rehash fi } function bundle(){ $HOME/.rbenv/shims/bundle $* if [ "$1" = "install" ] || [ "$1" = "update" ] then rbenv rehash fi }
では試してみましょう。
$ rspec rbenv: rspec: command not found # rspecコマンドは見つからない $ gem install rspec $ rspec /Users/kazuhisa/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/rspec-core-2.12.0/lib/rspec/core/configuration.rb:784:in `load': cannot load such file -- /Users/kazuhisa/spec (LoadError) #rspecを実行してテストファイルが見つからないのでエラーになってる
自動的にrbenv rehashしてくれてるみたいですね。良い感じです。
しばらくはrbenvを使ってみようと思います。
Scientific Linux release 6.3にQt4.8.xをインストールする
2012年11月9日にcapybara-webkitの0.13.0がリリースされました。このバージョンからQt4.6.x系ではコンパイルに失敗してしまうようです。現在テスト用サーバーとして使っているScientific Linux release 6.3にはyumでは4.6.x系までしかインストールできないようなのでソースを持ってきてコンパイルしてみました。
ダウンロードサイトはこちら。
http://qt-project.org/downloads
次の手順でインストールしました。
$ wget http://releases.qt-project.org/qt4/source/qt-everywhere-opensource-src-4.8.3.tar.gz $ tar zxvf qt-everywhere-opensource-src-4.8.3.tar.gz $ cd qt-everywhere-opensource-src-4.8.3 $ ./configure Which edition of Qt do you want to use ? Type 'c' if you want to use the Commercial Edition. Type 'o' if you want to use the Open Source Edition. o [Enter] This is the Open Source Edition. You are licensed to use this software under the terms of the Lesser GNU General Public License (LGPL) versions 2.1. You are also licensed to use this software under the terms of the GNU General Public License (GPL) versions 3. Type '3' to view the GNU General Public License version 3. Type 'L' to view the Lesser GNU General Public License version 2.1. Type 'yes' to accept this license offer. Type 'no' to decline this license offer. yes [Enter] $ gmake $ sudo gmake install
最後に.bashrcにpathを追加しました。
$ vi ~/.bashrc PATH=/usr/local/Trolltech/Qt-4.8.3/bin:$PATH:$HOME/.rvm/bin # Add RVM to PATH for scripting
MacOSXと比較してLinuxのcapybara-webkitは動作が非常に遅いのですが、新バージョンで改善してるといいな。
半分ジョーク、半分マジ ken_allをRubygemsで公開しました
今年の夏、FizzBuzz 問題どや顔で解くひとなんかよりも "KEN_ALL.csv" をうまく扱える人の方が社会的貢献度高いという話題がtwitterで盛り上がったのを覚えていますでしょうか?私もそのときは「そんなんあったなぁ。懐かしい」と思っていたのですが、秋になってから隣の席の人がKEN_ALL.CSVの扱いでキレて頭を悩ませてるのをみて、社会的貢献をしようと思い立ったわけです。
...嘘です。Rails Engineを使ったgemを作りたいなぁと思っていたところにネタが転がってきただけです。手段のためには目的は選ばないのです。
ken_all | RubyGems.org | your community gem host
使い方
Railsで簡単に最新の郵便番号情報をネットから取り込むことができます。
1.Gemfileに追加
gem "ken_all"
2.プロジェクトのディレクトリでrakeタスクを実行
$ rake ken_all:install:migrations #migrationファイルをプロジェクトに作成 $ rake db:migrate #テーブルの作成 $ rake ken_all:import #郵便番号の取込
取り込んだデータはKenAll::PostalCodeモデルで使用することができます。
詳細はGithubのREADMEを見て下さい。
Rails Engineについて
Rails EngineとはRailsで作成したアプリケーションの一部を他のアプリケーションに取り込むことができる機能です。Rails用ページネーションとして有名なKaminariもRails Engineを使用して作られているそうです。
Engineで私が気に入った点はテストのしやすさです。
開発中のEngineはdummyディレクトリ以下に作成されているRailsプロジェクトでいつでも実行することができます。rspec(※)も通常のRailsプロジェクトでやってる通りに書くことができます。
※Rails Engineでtest unitではなくrspecを使う方法はwhile(false){.net}: Testing Rails Engines With Rspecの手順で行けます
KEN_ALLの不思議な魅力
KEN_ALL.CSVは業務システムを構築する人は一度は通る道だと思います。本家「日本郵便」が配信しているデータにもかかわらず仕様があやふやなまま何度も手直しされて今に至っているのが、データを軽く眺めるだけでも理解できます。具体的には郵便番号データの落とし穴や郵便番号データの落とし穴」に落ちてしまいました。に詳しく解説されているとおりです。
おそらくパンチャーの方が汎用機に向かって一つ一つ手入力されているのでしょう。長い住所を途中で改行し複数行のデータを作るのはとても大変な作業だとお察しします。
そう、無機質であるはずのデータの向こうに人のぬくもりを感じるのです!
これって素晴らしいことだと思いませんか?
しかし、現実的には良い感じに手直しした郵便番号データをzipcloudさんが提供してくださってるのでそちらを使うののが正しいです。
ただ、データを眺めるうちに私は何とかしてプログラム処理のみで整形できないか試してみたくなったのです。
具体的にはzipcloudさんのページに書かれている解説の通りの処理を行なっているのですが次の部分だけは処理することができませんでした。
・町域名で、丸括弧で囲まれている部分を除去 ※町域名の文字数が多いために複数行に分割されてしまっている場合は、1行にマージしておいてから丸括弧を除去します。 ※括弧内の文字が「地名」や「ビルの階」など、住所として使えそうなものは町域名の末尾に追加します。 ※括弧内に地名が複数列挙されている場合は複数行に分割します。
郵便番号データの町域名のカッコの扱いは非常に曖昧で、色々な使われ方をしています。何とかルールを見出してプログラムで処理したかったのですがうまくいきませんでした。
なので、ken_allのgemも外部ファイルを取り込む機能を使ってzipcloudさんのデータをimportするのが現実的かなと思っています。
$ rake ken_all:import:file FILE=/path/to/x-ken-all.csv #外部のファイルから取り込みます