Vim で ^M を一括削除

Rails でジェネレーターを実行したら、ファイルの末尾に余分な改行コード ^M が追加されてしまったので、Vim でまとめて削除する方法をメモしとく。

コマンドモードに切り替えて

:%s/^M//g

を実行すればいい。 なお、^MCtrl-V Ctrl-M を押して入力する。

牛亭

肉が食べたい気分だったので、 六本松駅から歩いて15分、大濠公園すぐ側にある『牛亭』に行ってみた。 この店は人気らしく、ランチは予約しないとすぐ満席になってしまうみたい。 そうとも知らず予約なしで行ったら、運よくカウンター席が開いていた。 危なかったな。

f:id:griefworker:20140705114645j:plain

A ランチ(ポーク炭火焼+ハンバーグ)と手造りハンバーグステーキがよく注文されているみたいで、 どちらにするか迷ったけど、今回はハンバーグを注文。

f:id:griefworker:20140705115727j:plain

ハンバーグは鉄板いっぱいに広がっていて、予想以上のボリューム。 ソースはデミグラスソース。やっぱりハンバーグはデミグラスでしょ。 ソースをよく絡めて食べると旨い。

f:id:griefworker:20140705114947j:plain

サラダはコールスローみたいだった。

f:id:griefworker:20140705115743j:plain

ライスとパンを選べたので、ライスを選択。 肉にはライスが一番合う。

あと、アフターのコーヒーがついて、1200 円(税抜)。 増税の影響か、値段が上がっていて少々お高い印象を受けた。 以前は 1050 円(税込)だったらしいので、200 円以上の値上がり。 1080 円だと良かったのに。 まぁ、ハンバーグはボリュームあったし、コーヒーも付いていたから、 そう考えると 1200 円(税抜)でも納得だな。

関連ランキング:ステーキ | 六本松駅唐人町駅大濠公園駅

Grape で API を複数ファイルに分けて定義する

Grape では 1 ファイルに API をずらっと書けるけど、 規模が大きくなってくると見通しが悪くなるので、複数ファイルに分割したくなる。

Grape では API が他の API をマウントできるので、 その機能を使ってリソースごとにファイルを分割できる。

以下、サンプル。ヘルパーも別ファイルに切り出してみた。

posts.rb
# coding: utf-8
module API
  class Posts < Grape::API
    resource :posts do
      desc "投稿をすべて取得"
      get do
        # posts はヘルパーメソッド
        posts
      end

      desc "投稿を1件取得"
      get ":id" do
        posts.find(params[:id])
      end
    end
  end
end
helpers.rb
# coding: utf-8
module API
  module APIHelpers
    def posts
      Post.order(:id)
    end
  end
end
api.rb
# coding: utf-8
require_relative "helpers"
require_relative "posts"

module API
  class API < Grape::API
    format :json
    default_format :json
    prefix "api"
    version "v1", using: :path

    helpers APIHelpers
    mount Posts
  end
end

gem をオフラインでインストールする方法

あらかじめ Web に繋がったマシンで .gem ファイルをダウンロードしておけば

gem install --local <gem ファイル名>

でインストールできる。 ただし、依存する gem がインストールされていないと失敗するから、それらをすべて手動でインストールする必要があるため苦行。

Rails アプリで使う gem をまとめてオフラインインストールしたい場合、あらかじめ

bundle package

でインストールしている gem を vendor/cache に出力。 そして、まだ bundle install していないプロジェクトに vendor/cache をコピーして

bundle install --path vendor/bundle --local

を実行できれば、まとめてインストールできる。 依存している gem をいちいち手動で入れる必要がないので、こちらは楽。

paranoia を使った論理削除でコールバックを実行しない

paranoia を使った論理削除では、destroy したとき deleted_at が設定されるだけでなく、コールバックも実行される。

そのため

class User < ActiveRecord::Base
  acts_as_paranoid

  has_many :items, dependent: :destroy
end

上記の User で destroy を実行すると items が削除される。

論理削除でコールバックが実行されるのが今回都合が悪かったので、paranoiaソースコードを見ながら、destroy を上書きして対処してみた。

class User < ActiveRecord::Base
  acts_as_paranoid

  has_many :items, dependent: :destroy

  def destroy
    # paranoia で定義されているメソッドを呼び出して、
    # deleted_at に時間をセット
    result = touch_paranoia_column(true)
    result ? self : false
  end
end

その場しのぎ感が強いので、他の方法を考えたほうがいいかも。dependent オプションを外すとか。とりあえずメモしておく。

Apartment を使った Rails アプリを Heroku にデプロイできない

マルチテナント用の gem である apartment を使っている Rails アプリを、 Heroku に push すると下記のエラーが発生した。

Preparing app for Rails asset pipeline
       Running: rake assets:precompile
       rake aborted!
       Gem::LoadError: Specified 'sqlite3' for database adapter, but the gem is not loaded. Add `gem 'sqlite3'` to your Gemfile (and ensure its version is at the minimum required by ActiveRecord).
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.0/lib/active_record/connection_adapters/connection_specification.rb:190:in `rescue in spec'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.0/lib/active_record/connection_adapters/connection_specification.rb:187:in `spec'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.0/lib/active_record/connection_handling.rb:50:in `establish_connection'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/apartment-0.24.3/lib/apartment/adapters/abstract_adapter.rb:82:in `block in process_excluded_models'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/apartment-0.24.3/lib/apartment/adapters/abstract_adapter.rb:81:in `each'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/apartment-0.24.3/lib/apartment/adapters/abstract_adapter.rb:81:in `process_excluded_models'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/apartment-0.24.3/lib/apartment/database.rb:18:in `init'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/apartment-0.24.3/lib/apartment/railtie.rb:31:in `block in <class:Railtie>'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/activesupport-4.1.0/lib/active_support/callbacks.rb:438:in `instance_exec'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/activesupport-4.1.0/lib/active_support/callbacks.rb:438:in `block in make_lambda'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/activesupport-4.1.0/lib/active_support/callbacks.rb:184:in `call'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/activesupport-4.1.0/lib/active_support/callbacks.rb:184:in `block in simple'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/activesupport-4.1.0/lib/active_support/callbacks.rb:185:in `call'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/activesupport-4.1.0/lib/active_support/callbacks.rb:185:in `block in simple'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/activesupport-4.1.0/lib/active_support/callbacks.rb:86:in `call'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/activesupport-4.1.0/lib/active_support/callbacks.rb:86:in `run_callbacks'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/actionpack-4.1.0/lib/action_dispatch/middleware/reloader.rb:83:in `prepare!'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/actionpack-4.1.0/lib/action_dispatch/middleware/reloader.rb:55:in `prepare!'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/railties-4.1.0/lib/rails/application/finisher.rb:52:in `block in <module:Finisher>'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/railties-4.1.0/lib/rails/initializable.rb:30:in `instance_exec'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/railties-4.1.0/lib/rails/initializable.rb:30:in `run'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/railties-4.1.0/lib/rails/initializable.rb:55:in `block in run_initializers'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/railties-4.1.0/lib/rails/initializable.rb:54:in `run_initializers'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/railties-4.1.0/lib/rails/application.rb:288:in `initialize!'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/config/environment.rb:5:in `<top (required)>'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/activesupport-4.1.0/lib/active_support/dependencies.rb:247:in `require'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/activesupport-4.1.0/lib/active_support/dependencies.rb:247:in `block in require'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/activesupport-4.1.0/lib/active_support/dependencies.rb:232:in `load_dependency'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/activesupport-4.1.0/lib/active_support/dependencies.rb:247:in `require'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/railties-4.1.0/lib/rails/application.rb:264:in `require_environment!'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/railties-4.1.0/lib/rails/application.rb:367:in `block in run_tasks_blocks'
       /tmp/build_4f21ff1d-af6a-46cb-ba2e-935e4be9cdd8/vendor/bundle/ruby/2.0.0/gems/sprockets-rails-2.1.3/lib/sprockets/rails/task.rb:55:in `block (2 levels) in define'
       Tasks: TOP => environment
       (See full trace by running task with --trace)
 !
 !     Precompiling assets failed.
 !

 !     Push rejected, failed to compile Ruby app

Rails 初期化時に apartment の初期化を行っており、 database.yml に書かれている production 環境のアダプタを読み込もうとしてエラーが発生していた。 SQLite のアダプタを読み込もうとしたのが原因みたい。

Heroku に push したとき、 Heroku Postgres を使うように database.yml が自動で書き換わるんだけど、 Rails 初期化のタイミングではまだ書き換わっていなかったようだ。

database.yml で

production:
  adapter: postgresql
  host: HerokuPostgresホスト名
  port: 5432
  username: ユーザー名
  password: パスワード
  database: データベース名

という風に、SQLite ではなく PostgreSQL のアダプタを使うように書いておけば回避できた。

サーティワン

今日でついに 31 歳になってしまった。 31、サーティワン。旨そうな響き。 そういえば先週、もうすぐ 31 になるからって、 サーティワンのアイスクリームを食べたな。 その日は日差しが強くて暑かったので、実に旨かった。

今までアラサーなんて言ってたけど、31 歳にもなればアラサーとは言えないかも。 もはやアラサーじゃなくてサーだな。 何言ってるのか良くわからないだろうけど、 自分も何言ってるのかわかってないから、まぁいい。

さて、だいたい一年のうち半分が過ぎたわけだけど、 正月に立てた目標「アプリやサービスをリリースしまくる」の進捗は思わしくない。 今年に入ってまだ何もリリースしてないし。 RubyMotion でアプリを作り直したくらいだけど、こいつはノーカウント。

今プライベートで関わっている Rails のプロジェクトがあるので、 それを秋までにはリリースして、 あと Swift でアプリを1~2個作りたいところ。 Web サービスとアプリ、どちらもデザインがネックなんだよな。 コーディングはさくさく進むんだけど、いつもデザインでペースダウン。 いい加減そろそろ本気でデザインの勉強もしたほうがよさそうだ。

最近、やりたいことが多くて時間が足りない。 時間の使い方も見直さなければいけないな。

最後にアサマシエイトを貼っておく。

http://www.amazon.co.jp/registry/wishlist/13B3447YOJQNZ