あれ?error_logにもブラウザにもエラーが出てこない。の対処

問題:
CakePHPで作ったアプリがウンともスンとも言わない(ブラウザに白い画面が出る)。
php.iniでは下記の通り、エラーを報告する設定になっている

log_errors = On
error_reporting = E_ALL & ~E_NOTICE
display_errors = On

という状況。

解決:
core.php

Configure::write('debug', 0)

になっていたのを

Configure::write('debug', 2)

にする。

さくらの専用サーバ(CentOS)にRailsの実行環境を作る

表題の件、手順をメモ。

(1)各種インストール

su
yum install emacs
yum install ruby
yum install rubygems
gem install rails -v=2.3.2
gem install passenger
gem install ruby-devel
gem install httpd-devel
passenger-install-apache2-module

(2)下記の内容で /etc/httpd/conf.d/rails.conf を作る

LoadModule passenger_module /usr/lib/ruby/gems/1.8/gems/passenger-2.2.5/ext/apache2/mod_passenger.so
PassengerRoot /usr/lib/ruby/gems/1.8/gems/passenger-2.2.5
PassengerRuby /usr/bin/ruby

RailsAllowModRewrite on
RailsMaxPoolSize 4
RailsPoolIdleTime 30

NameVirtualHost XXX.YYY.ZZZ.WW:80


   ServerName hoge.jp
   ServerAlias www.hoge.jp
   DocumentRoot /RAILSROOT/rails/public
   AddDefaultCharset UTF-8
   RailsBaseURI /
   RailsEnv production
   RailsAllowModRewrite off
   PassengerEnabled on

ActiveRecordのupdated_at、created_atを自動更新しない方法

railsのモデル(ActiveRecord)にはtimestamps(updated_atとcreated_at)というフィールドがあって、更新日時、生成日時が勝手に記録されて便利ですね。
でも特定のタイミングでこの自動更新(特にupdated_at)を止めたい場合があります。

そんな時にはActiveRecord::Baseのrecord_timestampsをfalseにするといいみたいです。

例えば、僕の場合:
CMSみたいな仕組みを作っている
・ページの中身を入れておくPageというモデルがあった。
・このモデルにアクセスカウンター(pages.counter)用のフィールドあり。
・アクセスカウンターは/pages/showが呼ばれる度にpages.counterを+1する仕組み
・ということは/pages/showが呼ばれる度にupdated_atが更新される
・/pages/indexではページの内容が更新された順に並べたい
・updated_at DESCでソートしても「最近閲覧されたページ順」になってしまう
・アクセスカウンターの処理ではupdated_atは更新してくれるな!

というわけで

Page.record_timestamps = false
page.count_up
Page.record_timestamps = true

という感じのコードになりました。

migrationの新機能(redo, rollback)

実はそんなに新しい機能じゃないっぽいけど、最近知ったのでメモ
最近適用したmigrationを元に戻す(downを実行してくれる)

rake db:rollback

最新のmigrationを適用し直し(downとupをしてくれる)

rake db:migrate:redo

これまではmigrationのdownの部分って適当に書いてて、いざ実行してみると失敗して、DBの構造がよく分からんことになったりした。migrationファイルをコミットする前に一度redoを試しておくとdownの部分を含めて動作の確認が取れるので良いと思う。
2つ同時にコミットするなら

rake db:rollback STEP=2
rake db:migrate

とか。

自動生成したrspecのコードが失敗するときのメモ

rspecの低い(<= 1.2.2)バージョンを前提にgenerateされるコードが多いみたいなので、下記の修正が必要だったりします。


(1)route_forのパラメータは数字(integer)じゃなくて文字列(string)にする

○ route_for(:controller => "comments", :action => "index", :entry_id => "1").should == "/entries/1/comments"
× route_for(:controller => "comments", :action => "index", :entry_id => 1).should == "/entries/1/comments"


(2)route_forの右辺には:methodも含める

○ route_for(:controller => "acts", :action => "update", :id => "1", :manual_id => "1").should
== {:path => "/manuals/1/acts/1", :method => "PUT"}
× route_for(:controller => "acts", :action => "update", :id => "1", :manual_id => "1").should == "/manuals/1/acts/1"

※ GETの場合は文字列のみで良い


(3)formatted_XXX_pathは単にXXX_pathで良い
○ user_path(:id => '1', :format => 'xml').should == "/users/1.xml"
× formatted_user_path(:id => '1', :format => 'xml').should == "/users/1.xml"


参考:
rspec-rails 1.2.2やCucumber 0.2.0にあげるときの作業メモ
Rspec Rails、なんか仕様が変わった?

rspec_nested_scaffoldでネストした構造のscaffoldが一発生成

例えばブログ記事(Entry)の下にコメント(Comment)が複数ぶらさがっているとしますよね。
そいつを操作するプログラムを作る場合、routes.rbの指定は

map.resources :entrys do |entry|
 entry.resources :comments
end

とか指定するわけですよね。
でURLは「/entrys/1/comments」とかなるわけですよね。

こういう「URLをネストさせて」という構造、実は今まで嫌いでした。なんかメンドくさかったんですよね。ごちゃごちゃしてて。
でも「rspec_nested_scaffold」というのを知って、目から鱗が落ちましたね。「私がわるうございましたー!」みたいな。

script/plugin install git://github.com/phorsfall/rspec_on_rails_nested_scaffold.git
script/generate scaffold entry subject subject:string body:text
script/generate rspec_nested_scaffold comment body:text entry_id:integer --owner=entry

と実行して

config/routes.rb

map.resources :entries do |entries|
 entries.resources :comments
end

app/models/entry.rb

has_many :comments, :uniq => true

app/models/comment.rb

belongs_to :entry

app/views/entries/show.html.erb

%= link_to 'Show Comments', entry_comments_path(@entry) %> |

と追記すればOK! これで記事の下にコメントがついて、という構造を正しく処理してくれるプログラムが出来上がりです。

超カンタン!

ActiveRecordのhas_manyに:uniqを指定して重複を削除

ActiveRecordのhas_manyに:uniqを指定したときの動作を確認してみた。
グループの下に複数のユーザーがぶら下がっているテーブル構成を考える。

class Group < ActiveRecord::Base
  has_many :users, :uniq => true
end

class User < ActiveRecord::Base
  belongs_to :group
end

とか

class Group < ActiveRecord::Base
  has_many :users, :though => :groups_users, :uniq => true
  has_many :groups_users, :dependent => :destroy
end

class User < ActiveRecord::Base
  has_many :groups, :though => :groups_users, :uniq => true
  has_many :groups_users, :dependent => :destroy
end

という感じ。

consoleで

  • グループを作る g
  • ユーザーを作る u
  • 同じユーザーを何度も関連づける g.users << u
  • 重複して登録されているか確認する g.users.size

としてみる。

g = Group.create!
u = User.create!

10.times do 
 g.users << u
 p g.users.size
end

結果は

1
1
1
1
1
1
1
1
1
1

ということで重複なし。
:uniq => trueを付けない場合の挙動は以下。

1
2
3
4
5
6
7
8
9
10

という感じで重複して追加されていきます。

※ 中間テーブルを作らない1対多の構成( has_many :users と belongs_to :group の方)だと、そもそもテーブル構成的に:uniq=>trueなので、DB上は重複がない。