Rails Tutorial Chapter7をやる 断片的なメモ
英語版をやっていってるのですが、そろそろ日本語版も参考にしないと辛くなってきましたな・・・。
やったこと:
debug
メソッド経由でデバッグ情報を表示する- SassのmixinsでCSSルールのグループをまとめて複数の場所で再利用することができる。
- Railsには3つの標準的な環境がある。
development
,test
,production
- REST URLsの標準的なセットを通して
resource
としてユーザーと相互作用する(何を言っているのか(ry) - Gravatarを使えばユーザーの画像を表示するのに便利。
form_for
ヘルパーでActive Recordのオブジェクトと相互作用するフォームを作成することができる。- サインアップに失敗した際、ユーザーの新規作成画面をレンダリングし、エラーメッセージを出す。そのエラーメッセージはActive Recordにより自動的に決定される。
- 一時的なメッセージを表示するには
flash
が標準的なやり方。 - サインアップが成功した際にはDBにユーザーを作成し、その詳細ページにリダイレクトする。そしてウェルカムメッセージを表示する。
- 結合テストを行い、フォームから登録する振る舞いと回帰をキャッチする(何のことを言っているのか(ry)
- セキュアな伝達のためのSSLと、高いパフォーマンスのためのPuma(今回はUnicorn)を使用するように、本番環境のアプリに設定する。
参考記事:
Chapter 7: Sign up | Ruby on Rails Tutorial (3rd Ed.) | Softcover.io
7.1 Showing users
ユーザーのプロフィールページを作っていきます。
画像、ユーザー名、マイクロポスト、フォローしている数/されている数などを載せるのですが、今回はまず画像とユーザー名を表示させる。
7.1.1 Debug and Rails environments
プロフィールページを動的なものにしていくのですけど、デバッグ環境を整えるかと。
app/views/layouts/application.html.erb
<!DOCTYPE html> <html> . . . <body> <%= render 'layouts/header' %> <div class="container"> <%= yield %> <%= render 'layouts/footer' %> <%= debug(params) if Rails.env.development? %> # ここ </div> </body> </html>
development環境でのみデバッグ
Rails consoleはデフォルトではdevelopment
環境になっていると
$ rails c Loading development environment (Rails 4.2.0) irb(main):001:0> Rails.env => "development" irb(main):002:0> Rails.env.development? => true irb(main):003:0> Rails.env.test? => false
test環境でコンソールを動かしたいときは
$ rails c test Loading test environment (Rails 4.2.0) irb(main):001:0> Rails.env => "test" irb(main):002:0> Rails.env.development? => false irb(main):003:0> Rails.env.test? => true
Rails serverでもdevelopmentがデフォルトなので、本番環境でサーバー立ち上げたいときは
$ rails server --environment production
このようにするみたい(試してない)
そうなると本番環境のDBがないといけないので
$ bundle exec rake db:migrate RAILS_ENV=production
しかし今回の場合Herokuにデプロイしているのでherokuのコンソールを走らせると良い。
$ heroku run console >> Rails.env => "production" >> Rails.env.production? => true
デバッグの見た目をよくするため、スタイルシートに手を加えます。
app/assets/stylesheets/custom.css.scss
@import "bootstrap-sprockets"; @import "bootstrap"; /* mixins, variables, etc. */ $gray-medium-light: #eaeaea; @mixin box_sizing { -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; } . . . /* miscellaneous */ .debug_dump { clear: both; float: left; width: 100%; margin-top: 45px; @include box_sizing; }
.debug_dumpクラスでbox_sizingをインクルードしていると。何のことを言っているのか(略)
A mixin allows a group of CSS rules to be packaged up and used for multiple elements
CSSのルールのグループがパッケージされて、複数の要素に使用することができると?
同じborder-boxでも-moz-や-webkit-などのプレフィックスがついているのもあるので、それらをひとまとめにするということかな?
そして.debug_dumpクラスで取り込むと。それにより
.debug_dump { . . . @include box_sizing; }
これはこのように変換される。
.debug_dump { . . . -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; }
現在のコントローラとアクションが表示されている。(分かりにくいかw)
controller: static_pages action: home
7.1.2 A Users resource
URL/user/1でユーザーのプロフィールページにアクセスできるようにしたい。/users/1
でアクセスしても・・・
Started GET "/users/1" for 126.14.159.72 at 2015-02-13 04:39:37 +0000 ActionController::RoutingError (No route matches [GET] "/users/1"): web-console (2.0.0) lib/action_dispatch/debug_exceptions.rb:22:in `middleware_call' web-console (2.0.0) lib/action_dispatch/debug_exceptions.rb:13:in `call' actionpack (4.2.0) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call' railties (4.2.0) lib/rails/rack/logger.rb:38:in `call_app' railties (4.2.0) lib/rails/rack/logger.rb:20:in `block in call' activesupport (4.2.0) lib/active_support/tagged_logging.rb:68:in `block in tagged' activesupport (4.2.0) lib/active_support/tagged_logging.rb:26:in `tagged' activesupport (4.2.0) lib/active_support/tagged_logging.rb:68:in `tagged' railties (4.2.0) lib/rails/rack/logger.rb:20:in `call'
ルートがないよと。
routes.rbにてユーザーをリソースに加える。
resources :users
すると今度は、アクションないよと。
ならばshowアクションを作る。
class UsersController < ApplicationController def show @user = User.find(params[:id]) end def new end end
それに対応したviewをつくる。
/views/users/show.html.erb
<%= @user.name %>, <%= @user.email %>
単にユーザー名と、メールアドレスを表示するだけ。
そして/users/1
にアクセス。
下に表示されるデバッグにも
controller: users action: show id: '1'
と出る。
7.1.3 Debugger
Rails4.2ではbyebugというgemを使って、debuggerと加えれば良い、みたいな。
def show @user = User.find(params[:id]) debugger end
Rails serverのプロンプトにこのように出力される・・・はず。
なんどやっても504 Gateway Time-out
になってしまった。
(byebug) @user.name "Example User" (byebug) @user.email "example@railstutorial.org" (byebug) params[:id] "1"
デバッグ終わったら、Ctrl+Dで終了できる。そのあと、コントローラからdebugger
の記述を削除すれば良い。
これで何かしら変なところを調べるときにdebugger
仕込めば良いと。
7.1.4 A Gravatar image and a sidebar
ユーザー画像を表示させるためにここではGravatarから画像を取得する方法にしているようだ。まあgithubに登録するときにGravatarにも登録してたので、この方法でいきます。
GravatarのurlはメールアドレスのMD5 hashをベースにしているらしいので、Rubyのhexdigest
メソッドを使える。
>> email = "MHARTL@example.COM". >> Digest::MD5::hexdigest(email.downcase) => "1fda4469bcbec3badf5418269ffc5968"
emailをdowncaseしてあげて、それをhexdigestに渡す。
gravatar_for ヘルパーというのを作って、それを/users/showページで表示する。
app/helpers/users_helper.rbにgravatarヘルパーを定義
module UsersHelper # Returns the Gravatar for the given user. def gravatar_for(user) gravatar_id = Digest::MD5::hexdigest(user.email.downcase) gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}" image_tag(gravatar_url, alt: user.name, class: "gravatar") end end
emailからMD5 hashを生成し、それをurlの後ろにつける。
イメージタグヘルパーに、url指定。alt属性には名前、クラスにはgravatar
と名付ける。
そして
app/views/users/show.html.erb
<% provide(:title, @user.name) %> <h1> <%= gravatar_for @user %> <%= @user.name %> </h1>
provideはどこで受け取るのだろう? ああ、ここで受け取ってるんだった。
app/views/layouts/application.html.erb
<title><%= full_title(yield(:title)) %></title>
さらにApplicationHelperで定義したfull_title
ヘルパーメソッドに渡してるんだった。
(ここからはちょっとわけわからんメモ)
We’ll implement it using the aside tag, which is used for content (such as sidebars) that complements the rest of the page but can also stand alone.
今の場合サイドバーなので本文の部分からは外れている、ということなのかな?
<aside>
ってなんだろ。
http://www.marguerite.jp/Nihongo/WWW/RefHTML5/aside.html#SPECIFICATIONS
html5からのようだ。本文から外れたセクション?
HTML5でつまずきやすいasideとsectionの使い方 | KAYAC DESIGNER'S BLOG - デザインやマークアップの話
つまりasideはサイドバーをコーディングする時に使用してもいいという事になります。
(おわり)
出た・・・出たよ。ここで登録したユーザー名と、github,Gravatarでのユーザー名は微妙に違うけど。まあいいや。
真ん中でなくてサイドバーに表示したいので、Bootstrapのcol-md-*
を使う。
app/views/users/show.html.erb
<% provide(:title, @user.name) %> <div class="row"> <aside class="col-md-4"> <section class="user_info"> <h1> <%= gravatar_for @user %> <%= @user.name %> </h1> </section> </aside> </div>
app/assets/stylesheets/custom.css.scss
. . . /* sidebar */ aside { section.user_info { margin-top: 20px; } section { padding: 10px 0; margin-top: 20px; &:first-child { border: 0; padding-top: 0; } span { display: block; margin-bottom: 3px; line-height: 1; } h1 { font-size: 1.4em; text-align: left; letter-spacing: -1px; margin-bottom: 3px; margin-top: 0px; } } } .gravatar { float: left; margin-right: 10px; } .gravatar_edit { margin-top: 15px; }
.gravatar_edit
なんてあったっけ?
9章で使うみたい。
サイドにアイコンが寄っている。
7.2 Signup form
サインアップのための画面を作っていくのですけど、その前に一旦作成したユーザーを削除しようと。手っ取り早いのが、
$ bundle exec rake db:migrate:reset
これでリセットする。
$ rails c $ > User.all User Load (31.5ms) SELECT "users".* FROM "users" => #<ActiveRecord::Relation []>
Userが空っぽになってる。
form_for
ヘルパーを使います。まずusers_controllerのnewアクション内でUser.new
します。
class UsersController < ApplicationController def show @user = User.find(params[:id]) end def new @user = User.new end end
で新規登録画面の作成。フォームを用意する。
app/views/users/new.html.erb
<% provide(:title, 'Sign up') %> <h1>Sign up</h1> <div class="row"> <div class="col-md-6 col-md-offset-3"> <%= form_for(@user) do |f| %> <%= f.label :name %> <%= f.text_field :name %> <%= f.label :email %> <%= f.email_field :email %> <%= f.label :password %> <%= f.password_field :password %> <%= f.label :password_confirmation, "Confirmation" %> <%= f.password_field :password_confirmation %> <%= f.submit "Create my account", class: "btn btn-primary" %> <% end %> </div> </div>
form_forの引数にnewアクションで生成したuserオブジェクトを渡す。
!? まあスタイル書いてないからこんなもんか。
app/assets/stylesheets/custom.css.scss
. . . /* forms */ input, textarea, select, .uneditable-input { border: 1px solid #bbb; width: 100%; margin-bottom: 15px; @include box_sizing; }
うん、ましになったぞ。さらに加える。
input { height: auto !important; }
ふむ。
(The benefit of using an email field is that some systems treat it differently from a text field; for example, the code type="email" will cause some mobile devices to display a special keyboard optimized for entering email addresses.)
なんかemail_field
を使うのは色々捗るらしい。モバイル端末の中にはメルアドを入力するのに適した特別なキーボードを表示してくれるようだ。
7.3 Unsuccessful signups
早速フォームからユーザー作成・・・の前に、失敗した場合の処理を書かなくては。
create>保存成功/失敗時の処理
class UsersController < ApplicationController def show @user = User.find(params[:id]) end def new @user = User.new end def create @user = User.new(params[:user]) # Not the final implementation! if @user.save # Handle a successful save. else render 'new' end end end
コメントにもあるようにまだ最終実行ではないよと。ただ与えた:user
パラメーターでnewして、それが保存されてるか/されていないかの分岐を書く。
失敗していたらrender 'new'
で画面はそのまま。
ここでわざと間違った形式で情報を入力してみるかと。メルアドの形式なんかが間違っとる。
name: "Foo Bar"
email: "foo@invalid"
password: "foo"
password_confirmation: "bar"
ForbiddenAttributesError
がでる。
Rails serverのコンソール上
Parameters: {"utf8"=>"✓", "authenticity_token"=>"pxdaY4hpeUJ5Yhs7eZLIe9ehx2XWRzzJPT0EmKc2xJWUkRM6CJK1tlm0WqDQKAo6BfjRHrb9k+1u5Tq6yWXxcw==", "user"=>{"name"=>"Foo Bar", "email"=>"foo@invalid", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Create my account"} Completed 500 Internal Server Error in 1358ms ActiveModel::ForbiddenAttributesError (ActiveModel::ForbiddenAttributesError): app/controllers/users_controller.rb:11:in `create'
http://railstutorial.jp/book/ruby-on-rails-tutorial?version=4.0#sec-signup_failure
日本語訳のサイトから引用しますと
ruby @user = User.new(params[:user])
以下とほぼ等価であるということです。
ruby @user = User.new(name: "Foo Bar", email: "foo@invalid", password: "foo", password_confirmation: "bar")
7.3.2 Strong parameters
以前のバージョンのRailsでは、モデル層でattr_accessibleメソッドを使用することで上のような危険を防止していましたが、 Rails 4.0ではコントローラ層でStrong Parametersというテクニックを使用することが推奨されています。Strong Parametersを使用することで、必須のパラメータと許可されたパラメータを指定することができます。
params.require(:user).permit(:name, :email, :password, :password_confirmation)
- paramsハッシュでは:user属性を必須とする。
- そして:name,:email,:password,:password_confirmationなどの属性を許可している。
app/controllers/users_controller.rb
class UsersController < ApplicationController . . . def create @user = User.new(user_params) if @user.save # 保存の成功をここで扱う。 else render 'new' end end private def user_params params.require(:user).permit(:name, :email, :password, :password_confirmation) end end
コントローラのuser_params
メソッド(private)にストロングパラメーターを設定。
それをUse.new(user_params)
としてuserオブジェクトに渡す。
/signup
にアクセス、また間違った情報を入力。
今度はエラーは出ず、render 'new'
によって新規作成画面のまま、となる。
しかしエラーメッセージを出さないとですね。
7.3.3 Signup error messages
error messagesをパーシャルで表示する。
ここでは、’shared/error_messages’というパーシャルをrender (レンダリング) している点に注目してください。これはRails全般の慣習で、パーシャルは複数のコントローラにわたるビューに対し、専用のshared/ディレクトリを使用するようにしています
そうなんや。app/views/shared/_error_messages
を作成しないといけない。
form-control
クラスはBootstrapのクラス
app/views/shared/_error_messages.thml.erb
<% if @user.errors.any? %> <div id="error_explanation"> <div class="alert alert-error"> The form contains <%= pluralize(@user.errors.count, "error" %>. </div> <ul> <% @user.errors.full_messages.each do |msg| %> <li>* <%= msg %></li> <% end %> </ul> </div> <% end %>
pluralize
ってなんだろな。
pluralizeの最初の引数に整数が与えられると、それに基づいて2番目の引数の英単語を複数形に変更したものを返します。このメソッドの背後には強力なインフレクター (活用形生成) があり、不規則活用を含むさまざまな単語を複数形にすることができます。
app/assets/stylesheets/custom.css.scss
. . . /* forms */ . . . #error_explanation { color: red; ul { color: red; margin: 0 0 30px 0; } } .field_with_errors { @extend .has-error; .form-control { color: $state-danger-text; } }
さらにRailsは、エラーページにある、divで囲まれたエラーCSSクラスfield_with_errorsを適用しています。
ん、これどこにあるん?
In addition, after an invalid submission Rails automatically wraps the fields with errors in divs with the CSS class field_with_errors. These labels then allow us to style the error messages with the SCSS shown in Listing 7.20, which makes use of Sass’s @extend function to include the functionality of the Bootstrap class has-error.
Railsでは自動的にdiv
内のエラーフィールドをfield_with_errors
クラスでラップする? よしなにやってくれるということかな。
field_with_errors
ではBootstrapの.has-error
クラスの機能をインクルードしている。
こんなんでました。
7.3.4 A test for invalid submission
assert_no_difference 'User.count' do post users_path, user: { name: "", email: "user@invalid", password: "foo", password_confirmation: "bar" } end
errorとなった場合、ユーザーは登録されないので、ユーザー数は変わらないはず。
before_count = User.count post users_path, ... after_count = User.count assert_equal before_count, after_count
と同じようなことをassert_no_difference 'User.count' do
でできるということか。
test/integration/users_signup_test.rb
require 'test_helper' class UsersSignupTest < ActionDispatch::IntegrationTest test "invalid signup information" do get signup_path assert_no_difference 'User.count' do post users_path, user: { name: "", email: "user@invalid", password: "foo", password_confirmation: "bar" } end assert_template 'users/new' end end
We’ve also included a call to assert_template to check that a failed submission re-renders the new action.
登録失敗したら、そのままnewページをレンダリングすることも確かめる。
assert_template 'users/new'
7.4 Successful signups
今度はサインアップに成功した場合ですが、そのためのテンプレートをまだ作っていません。
class UsersController < ApplicationController . . . def create @user = User.new(user_params) if @user.save redirect_to @user else render 'new' end end private def user_params params.require(:user).permit(:name, :email, :password, :password_confirmation) end end
redirect_to @user
saveした後にユーザーのプロフィールページにリダイレクトする。そのままオブジェクト渡せばいいのか。
flash[:success] = "Welcome to the sample app!" redirect_to @user
redirectする前にflashメッセージを定義。:success
というキーを指定。
そしてそれをレイアウトに仕込んで、画面に表示する。
irb(main):001:0> flash = { :success => "Successed!", :danger => "Failed!" } => {:success=>"Successed!", :danger=>"Failed!"} irb(main):002:0> flash.each do |key, value| irb(main):003:1* puts "#{key}" irb(main):004:1> puts "#{value}" irb(main):005:1> end success Successed! danger Failed!
Rails console上で試してみる。:success
,:danger
というキーを使う。
flashメッセージを画面に出す。
app/views/layouts/application.html.erb
<html> . . <body> <%= render 'layouts/header' %> <div class="container"> <% flash.each do |message_type, message| %> <div class="alert alert-<%= message_type %>"><%= message %></div> <% end %> <%= yield %> <%= render 'layouts/footer' %> <%= debug(params) if Rails.env.development? %> </div> </body> </html>
body>containerの頭にメッセージを仕込む。
flashのキー(:success or :danger)をmessage_type
に渡し、それをalert-<%= message_type>
という形で埋め込む。つまり
alert-success alert-danger
になる。これらはBootstrapのクラス。
7.4.3 The first signup
Rails Tutorialの名前とロゴが使えるそうなので、ユーザー登録に使う。パスワードは適宜。
Name: Rails Tutorial
Email: example@railstutorial.org
成功すると/users/1
にリダイレクトして、このように表示される。
コンソールで確認。
> User.find_by(email: "example@railstutorial.org") User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."email" = ? LIMIT 1 [["email", "example@railstutorial.org"]] => #<User id: 1, name: "Rails Tutorial", email: "example@railstutorial.org", created_at: "2015-02-14 05:33:02", updated_at: "2015-02-14 05:33:02", password_digest: "$2a$10$/x5W4mCkcQraL/Iqmc8vhu.XbuYYeFFzyHWAchK5wSM...">
routeを確認すると、users_path post users#createというふうに紐付いている。
というわけでテストでもpostで投げるよと。
7.4.4 A test for valid submission
test/integration/users_signup_test.rb
class UsersSignupTest < ActionDispatch::IntegrationTest . . . test "valid signup information" do assert_difference 'User.count', 1 do post_via_redirect users_path, user: { name: "Example User", email: "user@example.com", password: "password", password_confirmation: "password" } end assert_template 'users/show' end end
assert_difference
post_via_redirect
assert_template 'users/show'
が先ほど(失敗した場合のテスト)と違う点。
- ユーザー登録がされれば、ユーザーが1個増えて「(数に)違いがでる」
- 成功後は「リダイレクトされる」
- リダイレクト先は「ユーザーの詳細(show)ページ」
ということかと。
7.5 Professional-grade deployment
なんだかんだで調べながらで時間かかりましたが、とうとう行きます。
$ git add -A $ git commit -m "Finish user signup" $ git checkout master $ git merge sign-up
チュートリアルでは最後にまとめてコミットしてるようですが、実際にはこまめにコミットしていくことになるかと。とにかくマスターにマージですね。
SSL導入
デプロイされたアプリケーションが期待どおりに動作するために、SSLが本番環境で動作するための行を1つ追加します。そのためには、config/environments/production.rbファイルを リスト7.29のように変更します。
config/environments/production.rb
SampleApp::Application.configure do . . . # Force all access to the app over SSL, use Strict-Transport-Security, # and use secure cookies. config.force_ssl = true . . . end
コメントアウトされている部分を外すだけです。
リモートサーバーにSSLを設定する必要があるのだけれど、Herokuなら大丈夫だぜ! みたいなことが。
and luckily we won’t need it here: for an application running on a Heroku domain (such as the sample application), we can piggyback on Heroku’s SSL certificate. As a result, when we deploy the application in Section 7.5.2, SSL will automatically be enabled.
この後Unicorn設定しようず! とありますが、日本語版はここでHerokuにプッシュしちゃいますね。先にやろうかな。
$ git add -A $ git commit -am "Use SSL" $ git push $ git push heroku $ heroku run rake db:migrate
Bitbucketにプッシュしたあと、herokuにデプロイ。忘れずにherokuでマイグレーションを行う。
remote: ###### WARNING: remote: No Procfile detected, using the default web server (webrick) remote: https://devcenter.heroku.com/articles/ruby-default-web-server
herokuにプッシュしている間、よく見るとワーニングが出ている。
webrickじゃなくてunicornにしたほうがいいんですかねー?
デプロイしたページを確認してみる。Sign up now!ボタンを押すとユーザー登録ページに遷移する。
ユーザーの詳細ページはまだ登録後にしか出ないようになってる。
自分を登録してみた。Rails Tutorialも。
7.5.2 Unicorn in production
Ruby Default Web Server | Heroku Dev Center
Why not WEBrick
By default WEBrick is single threaded, single process. This means that if two requests come in at the same time, the second must wait for the first to finish.
WEBrickはあまり本番環境には適してないらしいです。
Rails TutorialではUnicornだが、HerokuではPuma推しだそうです。
Deploying Rails Applications with Unicorn | Heroku Dev Center
Heroku recommends using the Puma web server instead of Unicorn. If you are using Unicorn, your application is not protected against a slow client attack.
!? んー、でもとりあえずUnicornにするか・・・。
Gemfileに追加(のちに最初からコメントアウトされているのに気づきましたが、それは置いといて・・・)
group :production do gem 'pg' gem 'rails_12factor' gem 'unicorn' end
$ bundle install
.
.
Installing unicorn 4.8.3
.
.
config/unicorn.rbというファイルを作成
$ touch config/unicorn.rb
Deploying Rails Applications with Unicorn | Heroku Dev Center
上記ページにある設定をそのままコピペ。
# config/unicorn.rb worker_processes Integer(ENV["WEB_CONCURRENCY"] || 3) timeout 15 preload_app true before_fork do |server, worker| Signal.trap 'TERM' do puts 'Unicorn master intercepting TERM and sending myself QUIT instead' Process.kill 'QUIT', Process.pid end defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect! end after_fork do |server, worker| Signal.trap 'TERM' do puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT' end defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection end
アプリのルートディレクトリにてProcfile
というのを作ります。
$ touch ./Procfile
これをheroku公式からコピペ。
web: bundle exec unicorn -p $PORT -c ./config/unicorn.rb
一応テスト走らせたのち、
$ git add -A $ git commit -am "Use Unicorn in production" $ git push $ git push heroku
マイグレーションはもうしてあるから良いと。
content_tagヘルパーを使う
app/views/layouts/application.html.erbにてflashを実装した部分
<% flash.each do |message_type, message| %> <div class="alert alert-<%= message_type %>"><%= message %></div> <% end %>
これはあまり美しくないのでcontent_tag
ヘルパーを使用する。
<% flash.each do |message_type, message| %> <%= content_tag(:div, message, class: "alert alert-#{message_type}") %> <% end %>
比較
Before:
<div class="alert alert-<%= message_type %>"><%= message %></div>
After:
<%= content_tag(:div, message, class: "alert alert-#{message_type}") %>
クラスの値でmessage_type
を式展開させる。
Sublime Text2を使用しているのですけど
SublimeText(Windows、Mac)をSassで使いやすい設定にする | Web制作者のためのSassの教科書 - 公式サポートサイト
+Tabでスニペットってのが効かないなあ。tabをスペースに設定しているのが悪いのかなあ?