トップ 最新 追記

2012-07-04 [長年日記]

_ Dragonfly attachmentを持つレコードをコピーする場合には注意が必要

Dragonfly については以前紹介した通りで、普段触っているアプリではこれを使っている。表示のタイミングで変換が走るのは高負荷のサイトには向かないかもしれないけど、使い勝手には満足している。

で、今回はこの Dragonfly を使っている場合に気をつける必要のあるユースケースを見つけたのでまとめておこうと思う。

ActiveRecord + Dragonflyでの画像の削除のタイミング

Paperclip もそうかもしれないけど、Dragonfly はよくできていて

  • レコードの削除
  • レコード内の Attachment の変更

のタイミングで Attach していたファイルをちゃんと掃除してくれる。これによって無駄なファイルが残ってしまうといったことがなくなる。

そしてこの処理は ActiveRecord で言うと

before_save

のタイミングで実行される。

削除時にはファイルの参照はチェックしないので自前で

今回ハマったのは

  • コピーしたレコードで
  • 画像を変更したら
  • 他のレコードも参照していたファイルが消えてしまった!

というものです。

上の説明を読んでいればとても当たり前の話なんだけど、まぁそこはそれ。回避するには以下のいずれかの方法がありそう。

  1. 参照カウンタよろしく、同一の uid を持つレコードが before_save の段階で 2以上あったら削除を無効化
  2. コピーの段階で実体のファイルもコピー

今回使ったのは 1 の方法。

削除を無効化する具体的な方法

※ 以下のコードは dragonfly 0.9.12 のものであり、また回避用のコードは実際に動いているものとよく似ているけれど動作検証はしていません。

dragonfly の画像の削除は知らない間に行われるので、callback で処理しているに違いない。ということで、before_* で検索してみる。

すると

lib/dragonfly/active_model_extensions/class_methods.rb

           before_save :save_dragonfly_attachments
           before_destroy :destroy_dragonfly_attachments

こんな記述が見つかる。探すと今度は

lib/dragonfly/active_model_extensions/instance_methods.rb

     def save_dragonfly_attachments
       dragonfly_attachments.each do |attribute, attachment|
         attachment.save!
       end
     end

     def destroy_dragonfly_attachments
       dragonfly_attachments.each do |attribute, attachment|
         attachment.destroy!
       end
     end

という記述が見つかる。これはそれぞれ

lib/dragonfly/active_model_extensions/attachment.rb

の中にある

     def destroy!
       destroy_previous!
       destroy_content(uid) if uid
     end

     def save!
       sync_with_model
       store_job! if job && !uid
       destroy_previous!
       self.changed = false
       self.retained = false
     end

のようだ。destroy! は期待通りに動いているので、save! でも同様に呼び出されている

     def destroy_previous!
       if previous_uid
         destroy_content(previous_uid)
         self.previous_uid = nil
       end
     end

があやしい。そこでこんなことをしてみた。

class Photo < ActiveRecord::Base

  image_accessor :image

  after_validation do
    if self.image_uid_was and
       self.class.where(:image_uid => self.image_uid_was).count > 1
      self.image.instance_eval {
        def destroy_previous!
          ;
        end
      }
    end
  end

end
  • 例として Photo という Model を用意し
  • その中の image という attribute に画像を保存
  • ファイルを変更しようとしており(photo_uid_was が nil でなかったら)、同じ uid を参照しているものが他に存在していたら
  • destroy_previous! を無効化

している。

今まさに保存しようとしているインスタンスだけ destroy_previous! の中身を空にしてしまう黒魔術。

すでに入っている before_save の callback の前にこれを追加することができるならそれでいいと思う。やり方が分からなかったので、before_save よりも前に呼ばれる after_validation に突っ込んだ。

after_validation から呼ぶなら before_save そのものを skip するという手も使えそうだけど、他に callback をセットしてるとそれもややこしいので、いちばん影響なさそうで手っ取り早い黒魔術で片付けることにした。

これでコピーしたレコードの画像を差し替えても他のレコードでロストしない。

Tags: Ruby RubyGems

2012-07-07 [長年日記]

_ 新レンズのメガネ受け取ってきた

先日注文したメガネが仕上がったはず*1なので受け取りに行ってきた。

で、予備のメガネは J!NS PC カスタムなので

予想通り本物のブルーライトカットレンズについて語られた。

うん、知ってた。そういう店だって。知ってて安いから J!NS 買ってるんだ。いいものがいいものだってことくらい分かるよ。

まぁ収穫はあった。

レンズの色でなくコーティングでカットするレンズはむしろ青い

とは言え、ちなみにおいくらとは聞く気にならなかった。うん、そういうこと。

Tags: 日々

*1 連絡なかった。

_ auで通話 + WiMAX + テザリング + iPod touch

なんか今日は朝から出先を含めて高難度のリモートサポセンを断続的にやってたんだけど、PC を使わずに通話しながら調べものしたいという自分の要求に困っていた。

結論から言うと

  • WiMAX + WiFiテザリング + iPod touch ( 最近また持ち歩いている )

であれば CDMA 回線使ってないので通話と両立できることが実験できた。ただし電池バカ食いなのでほんとに緊急用の方法だと思う。ここら辺だとまともに使える場所も限られるしね。

ただこの実験しようにも通話中に WiMAX on にしようとしたらいきなり Evo がリセット掛かったり、復帰したと思ってもやっぱり on にならず、通常手順で再起動したらようやく on にできるなど、

その場でサクッとセットアップできるもんじゃないのかもしんない。

サポセンの内容? IEリセットして最初の画面を通過させただけなんだけど、えらく大変だったよ! 検索プロバイダを勝手にプロバイダって省略して伝えるとこっちは何しようとしているのか分からなくなるよ!

※ そういやこの過程で iPod touch で Evernote でオフラインノート使いたかったらプレミアム会員になってねって言われた。昔は Star して保存できてたのに、残念だな。

Tags: au WiMAX Mobile
本日のツッコミ(全1件) [ツッコミを入れる]

_ 会長@腹部 [エスパーじゃないかぎり無理なので、どうしても時間かかりますよね。よくわかります。日常です。。。]


2012-07-08 [長年日記]

_ 蛍光灯交換したり

昨日は雨だったけど、今日は曇りでキープできてるのでいろいろ捗る。

のんびり模様替えだの片付けだのしてたけど、仕上げに切れかけていた蛍光灯をリサイクルプラザに持ち込んで新品を買ってきて交換した。

おぉ、これが世界か。

Hello, World !

あとはスキを見ながら twitter から Evernote へメモを転送。最後は1時間くらい風呂に浸かりながらの作業。やっぱ風呂に浸かっててもケータイいじってたらプラマイゼロだな。

とは言え、すでに覚えてなかった gem の platform の話とかちゃんとまとめなきゃと思い出した。えがった。

そうそう。最近 iTS で買った Supeyfly を狂ったようにヘビーローテしていた。以前から興味あったけど、DRM 付きで買う気になれず、円盤買うのも億劫だったんだけど、iTS が全曲 DRM free になってたのを思い出して買ってみたのだった。

こういう客は少数なのかもしれないけどさ、業界の方、

おれたちゃ必要ない不自由に金払いたくないだけで、欲しいものには金出すんだよ。

なんでもない週末万歳。

Tags: 日々

2012-07-09 [長年日記]

_ 10.6のsipsは日本語フォルダ非対応

まとめ

OSX 日本語フォルダ
10.7 OK
10.6 NG

10.6 の sips はファイル名だけなら日本語ファイル名でも ok なんだけど、フォルダ名に日本語が入るとダメ。

なんでsips ?

ImageMagick も psd に一応対応してるんだけど、やっぱり比較的最近の Photoshop で作ったちょっと凝ったものになると再現性に難がある。

Mac には sips があり、これの方が対応はいい。

ということで試そうとしたらがっつり日本語フォルダ名を使いまくられてて 10.6 環境で詰みましたとさ。

Tags: OSX Image

2012-07-15 [長年日記]

_ 財布を新しくした

本当は髪を切りたかったんだけど、今週はちょうど休みにぶつかってしまったので、もう連休中には切れなくなってしまった。

去年の10年ものの鞄、先月の5年使ったメガネのレンズに続いて今月は10年使った財布の新調。いかん、買い物づいてる。この調子でいくと5年後の今頃にまた続けて買い物してる予感。

今までの財布はスエード?っぽい仕上げで汚れとか脂とかでもう真っ黒だし、この時期はすごくベタベタしちゃうのがだいぶ残念な感じだったのと、いよいよ小銭を入れる部分のボタンがもう力がなくなっていたので新しくしてみた。

今度のは反省してスエードじゃなくて銀擦り。なかなかよい感じ。なのはいいんだけど、ちょっと厚みが今までより出たのでポケットに入れるのはためらわれる感じに…。うーむ。慣れるかなぁ。

Tags: 日々

2012-07-16 [長年日記]

_ github pagesとjekyllを今さら練習

思うところがあって github pages と jekyll を試してみた。

github pages

2種類ある。

  1. username.github.com
  2. username.github.com/repos
username.github.com
github.com/username/username.github.com

という repository を作る。例えば wtnabe なら

github.com/wtnabe/wtnabe.github.com

になる。ここに index.html を push してやればほどなく

http://wtnabe.github.com

にアクセスできるようになる。(これ書いてる時点ではテストが置いてあるけど、いつまでもあると思っちゃダメよ)

username.github.com/repos

各 repository に gh-pages という branch を作る

ことで、この中の HTML や素材が

username.github.com/repos

という名前でアクセスできるようになる。

両方作ったらどうなるの?

2種類あると気づいた段階でピンときてたんだけど、どうもこの2種類の github pages は最終的に一つのディレクトリツリー上に展開されているようだ。

試しにやってみたところ

  1. github.com/wtnabe/wtnabe.github.com 内に /ical2gcal/index.html を作成
    • 作った /ical2gcal/index.html が wtnabe.github.com/ical2gcal/ に表示される
  2. github.com/wtnabe/ical2gcal に gh-pages branch を作る
    • 作った gh-pages が wtnabe.github.com/ical2gcal/ に表示される
  3. github.com/wtnabe/wtnabe.github.com/ical2gcal/index.html を編集
    • 今編集したファイルが表示される。つまり 1 に戻る。

という動きをした。

つまり username.github.com の github pages を作る際には各 repos の名前空間が conflict することになるので注意が必要。

作り方

Web UI から自動生成するのが楽だし template も選べてよいと思う。

特に repository の github pages を作る際はすでにある README を index の内容として読み込んでくれる機能もあるのでだいぶ楽。README を github 標準のスタイル以外でも表示できるというだけでもそれなりに意味があるし、ちょっとドキュメント書くかって気になりそう。

jekyll

github pages と言えば jekyll というか、もう生の HTML の編集なんてできませんて。

ということでこっちも試してみる。jekyll コマンドで

  • (デフォルトで) _site/ 以下に render 結果を生成
  • --server で localhost に確認用のサーバを起こす
  • --auto でファイルを監視して自動生成
    • ただし livereload のような仕組みはないのでそこは各自で reload するか工夫が必要

という感じで使える。

以前紹介した Middleman は Sinatra を使って Rails 風の layout で、tilt を使って各種のマークアップ形式や CoffeeScript などに対応していたが、こいつはそれに比べるとだいぶシンプル。

とは言えちょっとクセがあって、

  • --- で囲んでコンテンツのファイルを二層にしないと変換が機能しない。最低限 layout と title を YAML で定義する感じになると思う。
  • git や gem 関係で必要なものも放っておくと出力(コピー)される*1ので、_config.yml の exclude: に定義しておくとよい
  • Textile は使わなくても RedCloth のインストールは必須で、かつ正しく依存性解決してくれない
    • ここはだいぶ変だと思う*2

excludeの定義は例えばこんな感じ

exclude:
  - .git
  - .bundle
  - Gemfile
  - Gemfile.lock
  - _config.yml
  - _layouts
  - params.json
  - vendor

実はこの params.json が何してるのか、まだよく分かってない。github pages を auto generate させたら勝手にできてた。

jekyll on github pages

jekyll での生成をアテにして Markdown ファイルや _layout/ などのファイルを直接 push してやると、ほどなく render 後の正しい HTML を閲覧できるようになる。

この機能を正しく使うには localhost に jekyll の環境がないとすぐに確認できないので黒い画面が苦手な人には厳しいと思う。

逆に使わないなら jekyll は無関係に github pages は作れる。

まとめ

github pages と jekyll を同時に扱おうとして無駄にややこしくなってしまった。

github pages は単に HTML を置いておくことができる repository でその名前や branch にルールがあるだけ。

たまたま jekyll での生成をアテにしたファイルも置いておくことができるというだけ。

jekyll はー…個人的には Liquid の良さがよく分からないのと、Liquid を使いつつ Textile や Markdown だけ特別扱いしている jekyll の方針がなんかモニョモニョする。まぁ何かしら global な値を渡したりはしたいんだけど、テンプレートや値の渡し方は Middleman + Tilt の方がよさげに見える。たぶん対応を広げすぎない方がいいという判断であえて現状のような構成になってるんだろうけど。

あと github pages のドキュメント、リンクがループしてたりして全然さっくり分かる感じがしないのは割と残念。仕組みはいいのに。

リンク

Tags: Ruby Github Git

*1 例えば vendor/ 以下もそのまま!

*2 0.11.2時点の話

_ 夏だ

夕方の公園にて

今日はとにかく暑かった。夕方になって買い物に出た*1ついでの1枚。iPhone 4Sのカメラはレンズが優秀なのかソフトが優秀なのか両方か、大きさとスピードの割にとてもよく写るよなぁ。

Tags: 日々

*1 昼間は昼まで別な買い物してるんだけど

本日のツッコミ(全2件) [ツッコミを入れる]

_ 困ったもんだ。 [管理人への連絡先がないので悩んだのだけど。 bookmarkとlabのリンクが切れとります。ので報告です。 メー..]

_ 774 [ありがとうございます。参考になりました!]


2012-07-27 [長年日記]

_ RailsAdmin + Dragonfly + html5_validatorsでアップロード済みのファイルを認識しない

症状

RailsAdmin も html5_validators も高度すぎて全然ついていけませんが、こいつらがとても気が利いていてすごいということは分かってきました。

が、今日はちょっと困ったことの報告。それは

  • Rails 3.2.6 + RailsAdmin 0.0.5 + Dragonfly 0.9.12 + html5_validators 1.1.0 の組み合わせ
  • 画像が必須の Model を定義
  • データを編集するときにアップロード済みのファイルの存在を html5_validators が認識できずに怒られる

というものです。

怒られる部分の DOM の状態は以下のような感じ。

Model モデルの image という attribute に dragonfly の attachment を定義しています。

<div id="model_image_field"
     class="control-group dragonfly_type image_field ">
<label for="model_image" class="control-label">画像ファイル</label>
<div class="controls">
  <div class="toggle">
   <a target="blank" class="thumbnail"
      href="/media/BAhbBlsHOgZmIiAyMDEyLzA3LzMwLzEwXzQ5... ">
     <img src="/media/BAhbB1sHOgZmIiAyMDEyLzA3LzMwLzEwXzQ5... "
          alt="Bahbb1shogzmiiaymdeylza3lzmwlzewxzq5... ">
   </a>
   <input type="file"
          required="required"
          name="model[image]" id="model_image"
          data-fileupload="true">
  </div>
  <input type="hidden"
         name="model[retained_image]" id="model_retained_image">
  <p class="help-block">必須. </p>
</div>
</div>

ここで <input id="model_image" type="file" required="required"> に対して validationMessage が「ファイルを選択してください。」になっている状態です。

validity を見ると valueMissing が true です。

しかしこれって HTML を load して DOM パネル開いた段階でもう validation 終了してるんですね。すげー。

回避方法

とりあえず画像必須の Model で

 self.auto_html5_validation = false

で html5_validators を外しています。

Tags: Ruby Rails