Rails4: ActiveRecord polymorphicのjoins検索?(追記あり)


polymorphicをjoinsで記述する方法が分からず、ほとんどSQLで書いたことのメモです。

例えば動物と植物のデータテーブルがあって、研究報告書のテーブルを共有して使うような構造。

class Report < ActiveRecord::Base
  belongs_to :reportable, polymorphic: true
end
class Animal < ActiveRecord::Base
  has_many :report, as: :reportable, dependent: :destroy
end
class Plant < ActiveRecord::Base
  has_many :report, as: :reportable, dependent: :destroy
end

動物のコアラと植物のユーカリのレポートを検索して一覧に表示したい。

ここでの前提は、何らかの検索の結果としてのReportのコレクション reports が手元にあり、ここから検索を追加記述しなければならないということ。(つまり AnimalやPlan側からの開始でReportを抽出できない)
joinsで検索を追加できるだろうか?

調べたが分からなかったので、とりあえず期待を込めてこうだったらいいなで書いてみる。

koala_reports = repors.joins(:animals).where(:animals => {:specie => KOALA})
eucalyptus_reports = repors.joins(:plants).where(:plants => {:classification => EUCALYPTUS})
result = koala_reports | eucalyptus_reports

残念、やっぱりダメで1〜2行目で report は animalを持っていない、plants を持っていないという意味でエラーになる。ではreportabelだろうかとヤマカンをはる(多分かなり疲れていた)。

koala_reports = repors.joins(:reportabel).where(:animals => {:specie => KOALA})
eucalyptus_reports = repors.joins(:reportabel).where(:plants => {:classification => EUCALYPTUS})
result = koala_reports | eucalyptus_reports

当然、これも間違い。
仕方ないので、SQLでベタに書くことにした。

koala_reports = repors.joins("JOIN animals ON animais.id = reports.reportable_id AND reports.reportable_type = 'Animal' AND animals.specie = #{KOALA}")
eucalyptus_reports = repors.joins("JOIN plants ON plants.id = reports.reportable_id AND reports.reportable_type = 'Plant' AND plants.classification = #{EUCALYPTUS}")
result = koala_reports | eucalyptus_reports

なにかよい記述方法があるのだろうか。


【追記】

多分、repors.animals と repors.plants でアクセスできるようにモデルを書きかえた上で(前提が変わるか?)、以下で行けるのでは? Arelを使う。2015/03/04

result = repors.includes(:animals, :plants)
.where(Animal.arel_table[:specie].eq(KOALA)
.or(Plant.arel_table[:classification].eq(EUCALYPTUS)))
.references(:animals, :plants)

SwiftのextensionでUITextFieldにInset余白を追加(メモ)


UITextFieldにInset 10ピクセルの余白を追加する。
Objective-CではCategoryで鷹揚にやっていたことが、お手軽に書ける感じになった。

extension UITextField {
    func textRectForBounds(bounds: CGRect) -> CGRect {
        return CGRectInset(bounds, 10, 10)
    }
    func editingRectForBounds(bounds: CGRect) -> CGRect {
        return CGRectInset(bounds, 10, 10)
    }
}

iOSの軽いアプリならクラスのファイルの冒頭にでも書いてもいいかも。

Swiftで半角ASCII文字判定


前にもObjective-Cで同じ課題について書いたが、かなり昔の話しで正規表現を使うやり方だった。今回は NSCharacterSet を使う。

今回やりたいのは文字列の1文字目が半角文字か日本語漢字なのかの判定。

結論的には以下。titleStrの1文字目が半角文字かどうかを unicodeScalarsを使い、valueで判定。

let hankaku = NSCharacterSet(range: NSMakeRange(0x20, 0x7e))
let titleUniStr = titleStr.unicodeScalars
let initialChar = titleUniStr[titleUniStr.startIndex]
if hankaku.longCharacterIsMember(initialChar.value) {
    println("半角")
} else {
    println("全角")
}

なお、iOSには文字列の判定に使える以下のようなセットが予め用意されているが、これらは全角判定に使えない。なぜなら、漢字も下記の letters だし、全角の数字も下記の digits に含まれるからだ。

let letters = NSCharacterSet.letterCharacterSet()
let digits = NSCharacterSet.decimalDigitCharacterSet()
let alphanum = NSCharacterSet.alphanumericCharacterSet()

以上