ActionMailerのURLをサブドメインに対応させる

Railsを使っていても実はメールを使うようなところを担当したことがなかったので今更ActionMailerについて勉強中です。
ActionMailerの設定はenvironments/(production|development|test).rbとか、もしくはapplication.rbに書くのでしょうが、普通はenviroments以下だと思います。こんな感じですね。

config.action_mailer.default_url_options = { host: 'localhost:3000' }
config.action_mailer.default_url_options = { host: 'example.com' }

しかしですね、いろんな環境でお試しで動かしたい場合があると思うんですよ。ステージングとか。デモとか。

そういうときにどういう風にすればいいのか。
environments/staging.rbを作って対応、とかが正しいのかもしれませんが、面倒だなぁと思ってググっていたところ、すごい簡単な解決策が載ってたので紹介しておきます。

参考サイト: Rails 4 ActionMailer subdomain urls

class ApplicationController < ActionController::Base
  before_action :set_mailer_host

  private
    def set_mailer_host
      ActionMailer::Base.default_url_options[:host] = request.host_with_port
    end
end

リクエストを受けたサーバのドメインとポートをbefore_actionで設定してしまうんですね。アクセスされたドメインが設定されるので、サブドメインだろうが関係なし。うーん、スマート。


ionicのサンプルを動かしてみた。

今日はOkayama.rbの日だったので参加してきました。おのおの自由にやりつつ。今日は私は朝にブックマークしてたionicの調査をしていました。ionicはスマートフォンサイト用のフレームワークです。またRubyじゃないけど、AngujarJSを使いたいと思っているので、面白そうだなーと思って。

まずサンプルを動かしてみようと思ったので、とりあえずダウンロード。
ディレクトリ構成を見る限り、bower, gruntとかでできてるみたいだったので、いろいろと準備。

$ npm install

これで依存ライブラリがインストールされます。
grunt serverで動くんかなと思ったら、動かず!
githubのREAD MEを見たらちゃんと書いてありました。

  • まず、PythonでWebサーバを起動します。
    $ python -m SimpleHTTPServer 8000
    
  • 次に、gruntにsassのコンパイルを任せます。
    $ grunt watch
    
  • http://localhost:8000/examples/starters/ にアクセスして、サンプルを動かしてみましょう!

これでようやく動きました。まだサンプルコードは読めてないけれど、見た目は結構よさげです。また、リストのスクロールが普通にスクロールしようとすると、全然動きませんでした。なんでやねんと思っていたら、これは「スマートフォン」向けのフレームワークなので、指でスクロールすることを想定してあって、ドラッグじゃないとスクロールしないようになってました。すごい。もうちょい試してみようと思います。


Sassで入力要素のクラスをまとめて定義する。

できるかなー?と思ったらできたので書いておく。
なにがしたかったかというと、各要素(ここではinputタグとtextarea)で使えるクラスをサクッとくっつけたかった。
普通にやろうとすると、たぶんこうなる。

input[type=text].error, input[type=email].error, input[type=password].error, textarea.error {
  background-color: #FFE1E3;
}
input[type=text].size-small, input[type=email].size-small, input[type=password].size-small, textarea.size-small {
  width: 150px;
}
input[type=text].size-medium, input[type=email].size-medium, input[type=password].size-medium, textarea.size-medium {
  width: 300px;
}
input[type=text].size-large, input[type=email].size-large, input[type=password].size-large, textarea.size-large {
  width: 450px;
}

これって横に長くて見辛いし、変更があったら全部またやっていかないといけない。面倒過ぎで笑えない。どの要素でどのクラスが使えるかを把握するのもこれだとちょっとわかりにくい気がします。

しかし、Sassを使えばこんなふうに書ける。

%inputArea {
  &.error {
    background-color: #FFE1E3;
  }
  &.size-small {
    width: 150px;
  }
  &.size-medium {
    width: 300px;
  }
  &.size-large {
    width: 450px;
  }
}
input[type=text] {
  @extend %inputArea;
}
input[type=email] {
  @extend input[type=text];
}
input[type=password] {
  @extend input[type=text];
}
textarea {
  @extend %inputArea;
}

おー、エレガント。ビューティフル。見やすいですねぇ!
フォームの入力要素で使えるクラスを%inputAreaにまとめてしまえば楽チンじゃないかな?と思ったのでした。


実際にSassを書いてみた(for, each, extend)

とりあえずSass形式で保存はしてあるけれどほとんどネストくらいはしただけといううちの会社のプロジェクトを題材に、Sassのリファクタリングをやってみた。辞書代わりにSassの教科書を添えて。

Sassはどんどんバージョンアップしていってて、使える関数が増えているらしいのだけれど、使いたい関数がまだ使えなかった。今のSassのバージョンは、安定板は3.2.13らしい。使いたい関数は3.3にあった。早くでてもらいたい。バージョン3.3からは文字列を扱うための関数が充実しているようだ。

参考URL: Sass 3.3で追加された「関数」や「変更点」のまとめ解説

新しい関数が使えたら、もっとリファクタリングできたんだけれど、Railsのバージョンに従う。
よくあるクラス系はもうループで定義すればいいなと思った。こんなの。

@for $value from 1 through 10 {
  .mb#{$value * 5} {
    margin-bottom: 5px * $value;
  }
}

あとは背景をどんどん設定していくとか。

@each $color in red, blue, yellow, green {
  .bg_#{$color} {
    background-color: $color;
  }
}

共通部分をわかりやすく共通化するとか。

.btn {
  width: 200px;
  height: 65px;
  color: white;
  text-align: center;
  border: 1px solid #f00;
}

.btn_ok {
  @extend .btn;
  background-color: green;
}

.btn_ng {
  @extend .btn;
  background-color: red;
}

上記のようにすると、こんなcssが出るはず。

.btn, .btn_ok, .btn_ng {
  width: 200px;
  height: 65px;
  color: white;
  text-align: center;
  border: 1px solid #f00;
}

.btn_ok {
  background-color: green;
}

.btn_ng {
  background-color: red;
}

でも上記のだと、使うかどうかもわからないbtnクラスを定義することになりますね。これは邪魔っちゃ邪魔。不要なクラスは定義したくないよーという場合はこうする。

%btn {
  width: 200px;
  height: 65px;
  color: white;
  text-align: center;
  border: 1px solid #f00;
}

.btn_ok {
  @extend %btn;
  background-color: green;
}

.btn_ng {
  @extend %btn;
  background-color: red;
}

すると、こうなるはず。

.btn_ok, .btn_ng {
  width: 200px;
  height: 65px;
  color: white;
  text-align: center;
  border: 1px solid #f00;
}

.btn_ok {
  background-color: green;
}

.btn_ng {
  background-color: red;
}

うん、すっきり。出力されるcssはそこまで短くはなりませんが、自分が管理するscss側ではずいぶん短くなると思います。あとはmixinとか関数とかもあるけれど、そこまでは使いこなせてない。まぁ昨日の今日だから、それでもいいかなと割り切る。これからもっと使えるようになろう!


simple_formでwrapperを使ってみる

simple_formとbootstrapの組み合わせは最強だと思うんですが、事情によりbootstrapが使えない場合もあります。
そうなってくると、simple_formの見せ場が難しくなり、form_forでやる?みたいになりそうですが、それはもう私みたいにsimple_formとbootstrapに慣れた人には辛過ぎます。
simple_formは出力をカスタマイズするためのwrapperがありますから、これを使ってみましょう。
今回は、フォームをtableで定義するという方法を使います。

参考ページ:simple_form をTable 要素で使う

このページに倣って書いてみたのですが、これだとエラーメッセージがそれぞれの項目毎に出てくれませんでした。それは非常に困る。config.wrappersの書き方の参考になるものはないか?と思ってググっていたのですが、あまり見つからず。そう思っていたところに、bootstrapのconfig.wrappersを見ればいいんじゃないか?と思って確認したところ、これがビンゴ!すごいわかりやすいです。

SimpleForm.setup do |config|
// ...省略
// 最後に追記する
  config.wrappers :table, tag: :tr, class: :input, hint_class: :field_with_hint,
                  error_class: :field_with_errors do |b|
    b.use :html5
    b.use :placeholder
    b.optional :maxlength
    b.optional :pattern
    b.optional :min_max
    b.optional :readonly
    b.use :label, wrap_with: {tag: 'td'}
    b.wrapper tag: 'td' do |ba|
      ba.use :input
      ba.use :hint, wrap_with: {tag: :span, class: :hint}
      ba.use :error, wrap_with: {tag: :span, class: :error}
    end
  end
end

inputをwrapperのtdで括って、その中にhint, errorを持たせるようにすると、同一td内にヒントとエラーメッセージが展開されるようです。これで前に進める!