Nwht0xn1

Controllerから渡される "false" などの文字列をActiveRecordで適切に変換するCreated on 2016-04-26 by r7kamura

記事投稿後に自動でリンクをつぶやく機能を追加しました - WikiHub Help で使った実装の一部の説明。「投稿後にTwitterにリンクをつぶやく」という機能を実装するために、Articleモデルに tweetable_after_article_created という属性をattr_accessorで定義し、Viewに tweetable_after_article_created という名前でチェックボックスを用意した。こういうやつ。

image

問題

Controllerで params[:tweetable_after_article_created] を参照すると "false""true" という文字列が入ってしまう1。データベースに保存する場合はActiveRecordが勝手に falsetrue に変換してから保存してくれるが、今回は保存したい訳ではないので勝手に変換してくれない。

class ArticlesController < ApplicationController
  def create
    attributes = params.permit(:body, :title, :tweetable_after_article_created)
    @article = current_user.articles.create(attributes)
  end
end

対策

Rails 4ぐらいだと、ActiveRecord::Type::Boolean.new.type_cast_from_database を使うと適当に変換してくれるので、末尾に "?" を付けた版のメソッドを用意して、必ず falsetrue のどちらかを使うように取り計らう。

class Article < ActiveRecord::Base
  attr_accessor :tweetable_after_article_created

  after_create :tweet_article_link, if: :tweetable_after_article_created?

  private

  def tweet_article_link
    ...
  end

  # @return [false, true]
  def tweetable_after_article_created?
    ::ActiveRecord::Type::Boolean.new.type_cast_from_database(tweetable_after_article_created)
  end
end

  1. 今回の例のようなリクエスト経由で渡された値の変換処理をControllerが担当するべきかModelが担当するべきかという議論の余地はあるが、今回はModelが担当する判断が下されたと仮定して話を進める。