Thomas on Rails。楽しげなメロディーと共に大惨事連発してます。Railsエンジニアのお父さんはお子さんとうっかり見たら心を深くえぐられそうです。

日本語版

Original Version

歌詞(日本語版)

「じこはおこるさ」

スリルなんてちょっとなら楽しみさ
でもイライラすると事故が起きる
へっちゃらさ なんて知らん顔して
走っているとそんな時

事故がほら起きるよ いきなり来る
調子乗ってやってるとバチがあたる

事故がほら 起きるよ
いい気になってると
そうさ、よそ見してるその時に
事故は 起きるものさ

思いつきでやると きっと 失敗するよ
幸運の女神は気まぐれだから
ウキウキしてるとまっさかさま
忘れないで気をつけてね いつだって

事故がほら起きるよ 突然さ
運が無い時はしょうがない
なんとかしよう

事故がもし起きたら
落ち込まないで
うまくやれるようにがんばろうよ
事故は起きるものさ

”標識はいくつもあるのにさ
大事なモノばかり見落とすね”

そんな時必ずやってくる
二度とやらなければいいけど
事故がほら起きるよ いきなり来る
調子乗ってやってると
バチがあたる

事故がほら起きるよ
いい気になってると
そうさ、よそ見してるその時に
事故は起きるものさ

事故がほら起きるよ突然さ
運が無い時はしょうがない
なんとかしよう
事故がもし起きたら
落ち込まないで

「まぁ、自信過剰だと集中力なんて
たいがい散漫になっちゃうからね」

事故だ 事故だ
忘れてると事故は起こるさ
ほーら!

Lyrics

"Accidents Will Happen"

Thrills and spills on the railway, it's a life of happiness
But sometimes impatience can lead to carelessness
Some think they are smart cats, and some just know it all
But sooner or later we all find out that

Accidents happen now and again, just when you least expect
Just when you think that life is okay, fate comes to collect
Accidents happen now and again, when people or trains get smart
If you don't concentrate on the thing that you're doing
Accidents will happen, just like that

Your best-laid plans can turn upside down if you get too confident
Sometimes you will slip and slide if that's Lady Luck's intent
One minute you're riding high, the next you're on the ground
But please remember, whatever the weather
You must take care 'cause

Accidents happen now and again, sometimes just by chance
You gotta pick yourself up and dust yourself down
Put it down to experience
Accidents happen now and again
Just don't take it all to heart
If you don't concentrate on the thing that you're doing
Accidents will happen, just like that

The warning signs are there for us to see most of the time
But sometimes we take chances and ignore the danger signs
Fate can surprise you, with no reason or rhyme
Make sure you learn your lesson you'll know better next time

Accidents happen now and again, just when you least expect
Just when you think that life is okay, fate comes to collect
Accidents happen now and again, when people or trains get smart
If you don't concentrate on the thing that you're doing
Accidents will happen, just like that

Accidents happen now and again
Sometimes just by chance
You gotta pick yourself up and dust yourself down
Put it down to experience
Accidents happen now and again
Just don't take it all to heart
If you don't concentrate on the thing that you're doing
And whatever you're doin' is not what you're thinking
Accidents, incidents
Accidents, incidents, accidents happen, just like that!

怖話でcomment付ける対象なんて"怖い話"だけに決まってるじゃん!

class CreateComments < ActiveRecord::Migration
  def change
    create_table :comments do |t|
      t.text :body
      t.references :story

      t.timestamps
    end
  end
end

余裕過ぎワロタwww

1年後・・・

"怖い漫画"・・・だと・・・!?

\( ^o^)/ オワタ

じゃ、じゃあ、comic_commentsというテーブルを・・・(レガシー直行)

commentをcommentableにする

でも大丈夫、後からでもcommentableに移行できます。今回はacts_as_commentableを使いました。

# Gemfile:
gem 'acts_as_commentable', '2.0.1'
% rails g comment

modelとmigrationでファイルを上書きしそうになるけど上書きしない。

# app/models/comment.rb:
class Comment < ActiveRecord::Base
  include ActsAsCommentable::Comment
  belongs_to :commentable, polymorphic: true, counter_cache: true
end
# app/models/story.rb:
class Story < ActiveRecord::Base
  has_many :comments, as: :commentable, dependent: :destroy
  acts_as_commentable
  attr_readonly :comments_count
end
# app/models/comic.rb:
class Comic < ActiveRecord::Base
  has_many :comments, as: :commentable, dependent: :destroy
  acts_as_commentable
  attr_readonly :comments_count
end

polymorphicかつcounter_cache使う時は、相手先をreadonlyにしとく必要があるみたいです。

class AddCommentableToComment < ActiveRecord::Migration
  def up
    rename_column :comments, :story_id, :commentable_id
    add_column :comments, :commentable_type, :string, default: 'Story'

    add_index :comments, :commentable_id
    add_index :comments, :commentable_type
  end

  def down
    rename_column :comments, :commentable_id, :story_id
    remove_column :comments, :commentable_type
  end
end

これで既にコメントが沢山あってもcommentableへの移行がバッチリ。この調子でtag, category, voteもどんどんやっていこう!

怖話をruby1.9.3-p194、rails3.2.8にアップグレードしました。

ビビリなのでとりあえずconfig.active_record.whitelist_attributesはまだで。

@machidaさんがsassをcompassベースにしたりと、そろそろ少し複雑化してきたコードベースの負債を返済中。

>> helper.link_to 'foo', 'bar'
=> "<a href="\"bar\"">foo</a>"
>> app.users_path
=> "/users"
# config/application.rb
module Foo
  class Application < Rails::Application
    (snip)
    config.sass.preferred_syntax = :sass
  end
end

怖話に自分の投稿した怖い話にコメントが付いたらメール通知する機能を付けました。

受信トレイ - komagata@gmail.com - Gmail

Userにメール通知する/しないフラグを追加して、CommentObserverを書く。

# app/models/comment_observer.rb:
class CommentObserver < ActiveRecord::Observer                                                                          def after_create(comment)
    if comment.story.user.notify_comment
      mail = NoticeMailer.comment_notice(comment)
      mail.transport_encoding = '8bit'
      mail.deliver
    end
  end
end

拡張子をfoo.html.hamlとかにしとくだけでHTMLメールになるのも便利ですね。

怖話はスマホ向けWebサイトです。今のスマホのHTML5 Audioではサウンドノベル風に音を鳴らすのが難しいのでcordovaでアプリ版を作っています。

しかし、サーバー側で普通のブラウザからのアクセスなのか、cordovaからのアクセスなのか区別がつかない。数ページ程度だったらquery stringにでも何か付けてアクセスするようにすればいいけど、怖話はサイト全体に渡ってどちらからもアクセスされる可能性があるのでcookieが使えないガラケーのようなquery string引き回しなどはやりたくない。

StackOverflow駆け込み寺に問い合わせたところ、10minで答えが来た

「cordovaのソース弄ってヘッダ追加すれば?」

なるほどですねー!

% git diff
diff --git a/framework/src/org/apache/cordova/DroidGap.java b/framework/src/org/apache/cordova/DroidGap.java
index 5e2586d..dfbdb44 100755
--- a/framework/src/org/apache/cordova/DroidGap.java
+++ b/framework/src/org/apache/cordova/DroidGap.java
@@ -562,7 +562,9 @@ public class DroidGap extends Activity implements CordovaInterface {
                 };
                 Thread thread = new Thread(runnable);
                 thread.start();
-                me.appView.loadUrl(url);
+                HashMap headers = new HashMap();
+                headers.put("X-Access-From-Cordova", "true");
+                me.appView.loadUrl(url, headers);
             }
         });
     }

X-Access-From-Cordovaという勝手なヘッダを付けて、以前のエントリー通りcordovaをbuildして自分のプロジェクトに放り込む。

サーバー側(Rails)に下記helperを追加。

# app/helpers/application_helper.rb
module ApplicationHelper
  def cordova?
    request.headers['X-Access-From-Cordova'] == 'true'
  end
end

神様仏様StackOverflow大明神様 <3 <3 <3

Macを再インストールしたのでrvmが新しくなったからか、capれない。

% bundle exec cap staging deploy
/Users/komagata/.rvm/lib/rvm/capistrano.rb:5:in `': RVM - Capistrano integration was extracted to a separate gem, install: `gem install rvm-capistrano` and remove the `$LOAD_PATH.unshift` line, note also the 'set :rvm_type, :user' is now the default (instead of :system). (RuntimeError)

長いエラーをちゃんと読むと、rvmのcapistrano関連の部分はrvm-capistranoとして別gemになったようです。Gemfileに追加します。

group :development do
  gem 'rvm-capistrano'
end

また「$LOAD_PATH.unshiftしてんのを取れ」と出てるので大抵の人はRAILS_ROOT/config/deploy.rbに書いてる下記を取ればOK。

$:.unshift(File.expand_path('./lib', ENV['rvm_path'])) # REMOVE ME!

コンパイラが変わるという大転換期なので仕方無いとは思いますが、Xcode依存のゴタゴタはプログラマーにも厄介。デザイナーさんに環境作ってと気軽に言い辛いここ最近のMac環境です…。

deviseはデフォルトでuserの更新(Devise::RegistrationsController#update)に現在のパスワード(current_password)が要る。

ソースを見てみるとmodelにupdate_without_passwordというのがあるのでこれかと思いきや、これはpasswordとpassword_confirmation無しでupdateするものだった。

自分でupdate_without_current_passwordを作る。

# app/models/user.rb:
class User < ActiveRecord::Base
  def update_without_current_password(params, *options)
    params.delete(:current_password)                                                                                  

    if params[:password].blank?
      params.delete(:password)
      params.delete(:password_confirmation) if params[:password_confirmation].blank? 
    end

    clean_up_passwords
    update_attributes(params, *options)
  end
end

controllerからもこれを使うようにする。

# app/controllers/registrations_controller.rb:
class RegistrationsController < Devise::RegistrationsController    
  def update
    @user = User.find(current_user.id)
    if @user.update_without_current_password(params[:user])
      sign_in @user, bypass: true
      set_flash_message :notice, :updated
      redirect_to after_update_path_for(@user)
    else
      render 'edit'
    end
  end
end

面倒ですね。

怖話ではさくらVPS512を使ってます。性能的にはまだ問題無いんだけど、HDD容量が20GBとちと不安。先日もproduction.logが1.7GBになってたのでちゃんとローテートする。

$ cat /etc/logrotate.d/kowabana 
/var/www/kowabana/shared/log/*.log {
  weekly
  missingok
  rotate 24
  dateext
  compress
  delaycompress

  lastaction
    pid=/var/www/kowabana/shared/pids/unicorn.pid
    test -s $pid && kill -USR1 "$(cat $pid)"
  endscript
}

newrelicのログとかunicornのログとかも一辺にローテートされるから楽でいいですね。-dをつければdry run。-fで強制実行。

sudo logrotate -df /etc/logrotate.d/kowabana

後は一日14MBぐらいずつ増えるDBのバックアップファイルを何とかしなきゃ。