Rails: Doorkeeperでのログイン処理中に起きたエラーをJSONで出力

Doorkeeperでログイン中にエラーが発生すると、Doorkeeper::TokensControllerの中でエラーが起きるので、ApplicationController < ActionController::Baseの中でrescue_fromを書いてもうまくハンドリングできなかった。これをrescueするための方法。エッセンスは以下の通り。

  • use_doorkeeperの中でdoorkeeperの処理に使うcontrollerを指定できる
  • Doorkeeper::TokensControllerはActionController::Metalを継承しているので、renderを実行するのに必要なmoduleをincludeする必要がある

/config/routes.rb

MyAppServer::Application.routes.draw do
  use_doorkeeper do
    controllers tokens: 'tokens'
  end

  resources :books
  resources :users
end

/app/controllers/tokens_controller.rb

class TokensController < Doorkeeper::TokensController
  include ActionController::Rescue
  include ActionController::Rendering
  include ActionController::Renderers::All

  rescue_from Exception do |e|
    render json: {error: 'something occurred.'}
  end
end

railsでsanitizeすると閉じタグを付け忘れた時にタグが続いてしまう

sanitizeというメソッドを使うと、ホワイトリストに載ったHTMLタグ以外を削除して出力できる。例えば以下のようなコード(haml)を書くと、

%p
  - dummy_text = '斜め'
  = raw(sanitize(dummy_text))
斜め

と出力される。

通常はこれで問題ないが、タグが閉じられないままだと、続けて出力されてしまう。

%p
  - dummy_texts = ['<i>斜め' '斜めったまま']
  - dummy_texts.each do |dummy_text|
    %p
      = raw(sanitize(dummy_text))

↓こんな感じ。

斜め
斜めったまま

つまり、validではないHTMLをvalidにするにはどうすればいいかという問題。

続きを読む railsでsanitizeすると閉じタグを付け忘れた時にタグが続いてしまう

Mongoidのany_ofがorではなくandになる

any_ofでorの結果を取得したいのに、結果はandになってしまう、という場合

User.any_of(:created_at.gte => 1.week.ago, :name => /^j/)

上記のコードは、1つのハッシュをany_ofとして渡している。any_ofはハッシュを複数渡すのが正解なので、以下のコードが正しい。

User.any_of({:created_at.gte => 1.week.ago}, {:name => /^j/})

よくミスするのでメモ。

Rails + HAMLの環境で、URL Helperを使いながらjQuery Templateを使う

JavaScirptで利用できるテンプレートエンジンに「jQuery Templates」がある。これにはjquery-tmpl-railsというgemも用意されていて、すぐに使い始めることができる。使い方のチュートリアルとしてはブログ記事”jQuery公式のテンプレートplugin 「jQuery Templates」-JavaScript Library Archive“が分かりやすい。

railsのurl helperを使うと、routes.rbに書かれた内容に沿ってURLを自動で生成してくれる。例えば、routes.rbにresource :booksと書いていた場合、指定のIDのBookのページのURLを取得するにはbook_path(:id)と書けばよい。詳しくは以下参照。
2.3 Paths and URLs – Ruby on Rails Guides: Rails Routing from the Outside In
この時、:idに相当する部分は自動でURLエンコードされる。ここをjQuery Templatesで書き換えたい場合、ダラー( $ )と波括弧( { と } )がエスケープされてしまう。それを避ける方法。

あまり綺麗な書き方ができなかったので、もっとベターな方法(例えばURLHelperの機能を使う時にURLエンコードを禁止するような方法)があったらどなたか教えてください。

Rails: コントローラとモデルのリファクタリング

railsのリファクタリングについて具体的な事例が掲載されていて分かりやすかったのでメモ。

Railsで目指せ、情熱エンジニア(10):コントローラとモデルをリファクタリングする
前回用意したRailsアプリのコントローラのテスト(スペック)をもとに、今回はコントローラとモデルのリファクタリングの実例を紹介します。
http://www.atmarkit.co.jp/ait/articles/1305/28/news003.html

Mongoidでcallback(before_save等)を呼ばずにupdateする

before_save, after_saveといったコールバックを実行せずにフィールドの値を更新するには、setメソッドを利用する。after_saveの中で値を更新したい時に便利。
以下は例。

item = Item.first
item.set(:description, "It's so nice!")

簡単ですね。

http://mongoid.org/en/mongoid/docs/persistence.html#atomic

ActiveRecordでcallbackを呼ばずにupdateする

ActiveRecord::Baseを継承したクラスの中で、before_save, after_saveなどを書くと、保存前や保存後に呼び出されるメソッドを指定できる。しかし、これらのコールバックの中で例えばsaveメソッドを実行してしまうと、stack level too deep (SystemStackError)というようなエラーが起きてしまう。

参考にしたのは以下のページ:
ruby on rails – Skipping callbacks and validation – Stack Overflow

以下のドキュメントにリストアップされているメソッドは、こういったコールバックを呼び出さずにスキップして、updateをかけることができる。
http://guides.rubyonrails.org/active_record_validations_callbacks.html#skipping-callbacks

続きを読む ActiveRecordでcallbackを呼ばずにupdateする

I18n.tで変数を使う/動的に翻訳を増やす

I18n.tを使ってyamlから文字列を読み込んでいる時、文中に変数名を入れたいことがある。その場合は、yaml側では変数名を%{ }と囲んで、I18n.tの引数としてハッシュを渡せばよい。詳しくは、以下のドキュメントに記載されていた。

http://guides.rubyonrails.org/i18n.html#interpolation

上記URLからサンプルコードを引用:

I18n.backend.store_translations :en, :thanks => 'Thanks %{name}!'
I18n.translate :thanks, :name => 'Jeremy'
# => 'Thanks Jeremy!'