ActiveRecord::Relation#merge

joinsと組み合わせて使うと関連モデルのスコープが利用できるようになる優れもの。

コード例を見るとわかりやすい。
以下は日記と日記にぶら下がるコメントのモデルを表す

class Diary < ActiveRecord::Base
  has_many :comments
  scope :title_like, lambda {|title|where('title LIKE ?', "%#{title}%")}
end

class Comment < ActiveRecord::Base
  belongs_to :diary
end

この時Commentに対し、親のDiaryのtitleで検索をしたい場合、mergeを使わないと例えば以下のようにる。

class Comment < ActiveRecord::Base
  belongs_to :diary
  scope :diary_title_like,
        lambda {|title| joins(:diary).where('diaries.title LIKE ?', "%#{title}%")}
end

Comment::diary_title_likeとDiary::title_likeはほぼ同じ処理になりDRYではない。


これをmergeを使うと以下のように書く事ができ、titleへのLIKE検索の処理を共通化できる。

class Comment < ActiveRecord::Base
  belongs_to :diary
  scope :diary_title_like,
        lambda {|title| joins(:diary).merge(Diary.title_like(title))}
end

Passing the format in the template name is deprecated. Please pass render with :formats => [:html] instead.

renderメソッドでビューのフォーマットまで指定するとタイトルのWARNINGが出る。


対処は以下の通り

# フォーマット(html)まで指定しているので×
render 'form.html'

# テンプレート名からフォーマットを排除し、代わりに:formatオプションに指定することで○
render :partial => 'form', :formats => [:html] 

Rails(3.1 or later) productionモードが動かない

Rails3.2.1 productionモードで起動し、アプリのトップページへアクセスしたらInternal Errorが発生。


production.logには以下が吐かれていた。
ActionView::Template::Error (application.css isn't precompiled):


ネットを探すと以下のページが見つかる。
http://d.hatena.ne.jp/takuti/20111011/1318335585

このページを参考に以下を行う事で解決したが・・・

rake assets:precompile



vi config/environments/production.rb

config.assets.compile = true


②が腑に落ちないなぁ。確かにこれやらないと解決しないんだけど、問題はそれ以前にある気がするなぁ。

accepts_nested_attributes_forに指定したアソシエーションは親が更新されると子も更新してくれる

accepts_nested_attributes_forってフォームから親子まとめて保存する時に使うものと思ってましたが、フォームを使わなくても親子をまとめて保存してくれるんですね。知らなかった、何て便利なのでしょう。

# ex
class Diary  < ActiveRecord::Base
  has_many :comments
  accepts_nested_attributes_for :comments
end

diary = Diary.first
# 変更前のコメントは以下だとします
diary.comments.first.content #=> '変更前のコメント'
# コメントを変更します
diary.comments.first.content = '変更後のコメント'
# この状態で親を保存します
diary.touch
# すると子も保存してくれる
diary.comments.first.content #=> '変更後のコメント'

上記の後、調べたところ親子をまとめて保存する際にaccepts_nested_attributes_forを使わずに、もっと素直にできることがわかった。
どうするかというとアソシエーションの:autosaveオプションをtrueに設定する。

class Diary  < ActiveRecord::Base
  has_many :comments, :autosave => true
end

Rubyで日本語の祝日を表示するライブラリ(holiday_jp)

Rubyで日本語の祝日を表示してくれるライブラリ(holiday_jp)の作者ブログ(http://docs.komagata.org/tags/holiday_jp/)から引用しますと

>>祝日は法律によって増えたり減ったりするので未来に渡って計算で算出することができません

考えてみれば確かにそうですね。なのでとっととholiday_jpの力を
借りることにしました。

こんな感じで使います。

holidays = HolidayJp.between(Date.new(2010, 9, 14), Date.new(2010, 9, 21))
holidays.first.name # 敬老の日

便利過ぎるなこりゃ。
でも一点だけ難を言うと、単日の祝日を取得するメソッドがないんだよな。何でだろ?

Rails3.2.0へのバージョンアップ

Rails3.2.0がリリースされたので、Rails3.1.3からバージョンアップしました。

その際にすんなりいかなかったので俺の歩んだ道を共有します。参考になれば幸いです。


①まずはRails3.2.0をインストール、これは成功します。
gem install rails -v 3.2.0


②Rails3.1.3とRails3.2.0差分を調査し、差異を自分のアプリに適用。(この作業いつも手作業でやっているんですがひょっとして自動化されているんでしょうか?)


すんなり行く時はこれで終わりですが、今回は駄目でした。
アプリのトップページにアクセスすると俺の場合ActiveRecord::ConnectionNotEstablishedが発生しました。


試しにrails cするとこちらも駄目で以下のエラーが出ました。
can't activate mysql2 (~> 0.3.10), already activated mysql2-0.3.7


③困ったのでRails本家サイトを見るとRuby1.9.3が推奨されており、自分は1.9.2だったので1.9.3にバージョンアップしましたが状況変わらず。(因みに1.9.3へバージョンアップするとbundle installでエラーが出るようになりました。これはこれで解決しましたがこの情報は機会があったら書くかもしれません)


④流れ流れて辿りついたのが以下のページ。
http://stackoverflow.com/questions/8618509/this-version-of-mysql2-0-2-18-isnt-compatible-with-rails-3-1


Gemfileを上記ページの通り変更することで解決。

gem "mysql2", "~> 0.3.11"

以上