Rails4 「incompatible character encodings: ASCII-8BIT and UTF-8」エラーが出た

自前でSQLを書いていたら、「incompatible character encodings: ASCII-8BIT and UTF-8」というエラーが出た。

ASCII-8BITとUTF-8が文字列中で混在してしまったようだ。
対策としては、下記のようにエンコーディング指定すればよい。

msg.force_encoding("utf-8")

参考:
Rails 4: incompatible character encodings: UTF-8 and ASCII-8BIT - Stack Overflow

Rails4 タイムゾーンを設定しているのに、Heroku上で日付に時差が生じてしまう

config\application.rbに下記のようにタイムゾーンを東京に設定している。

config.time_zone = 'Tokyo'

しかし、Date.todayなどを使用すると、Heroku上で時差が生じてしまった。
config\application.rbで設定したタイムゾーンを使うには、zoneを使うといいようだ。

Time.zone.now

しかし、Dateにはzoneが使用できないので、Timeを使って日付に変換するといいようだ。

Time.zone.now.to_date


参考:
Heroku で日付時刻の表示(9時間ずれて表示される問題の対処) - わからん
Rails 3: How to get today's date in specific timezone? - Stack Overflow

Rails4 PostgreSQLで数値を降順にソートしたらnullが先頭になってしまった

SQLite3では、点数を降順で並べる下記のようなスコープで、nullが末尾に来ていたが、PostgreSQLだと、nullが先頭に来てしまった。

scope :order_score_desc, -> { order(score: :desc) }


そこで、下記のように、(列名 is null)を追加してあげると、PostgreSQLでもnullが末尾に来た。

scope :order_score_desc, -> { order("(score is null)", score: :desc) }


もちろん、SQLite3でも正常に動作した。


参考:
WEB開発備忘録 PostgreSQLでorderする際の、null値の扱い

Rails4 3階層のincludesの複数指定

N+1問題解決のため、includesの設定をしていた。

groupがuserを参照しており、userがdepartmentとpostを参照しているとき、groupからdepartmentとpostの両方ををincludesで指定するのにちょっと手間取った。

group → user → department・post


下記のように書いたらうまくいった

@groups = Group.order(:id).
                includes({user: [:department, :post]})


関連:
Rails4 3階層のincludesの指定 - ayaketanのプログラミング勉強日記

Rails4 ActiveRecordでorを使用する簡単な方法

以前、ActiveRecordでorを使用する方法を見つけましたが、もっと簡単な方法がありました。
Rails4 ActiveRecordでorを使用する - ayaketanのプログラミング勉強日記


ユーザーが所属を3つ持つことができるとします。
ある所属に属するユーザーを抽出するには、下記のように記載します。

department1_id = User.arel_table[:department1_id]
department2_id = User.arel_table[:department2_id]
department3_id = User.arel_table[:department3_id]

User.where(department1_id.eq(department_id).or(department2_id.eq(department_id)).or(department3_id.eq(department_id)))


スコープにする場合、下記のように記載します。

scope :department_is, ->(department_id) {  department1_id = User.arel_table[:department1_id]
                                           department2_id = User.arel_table[:department2_id]
                                           department3_id = User.arel_table[:department3_id]
                                           where(department1_id.eq(department_id).or(department2_id.eq(department_id)).or(department3_id.eq(department_id))) }


参考:
ActiveRecord4でこんなSQLクエリどう書くの? Arel編 - TIM Labs

Rails4 ヘッダのみのCSVファイルをダウンロードする

CSVファイル読み込みのテンプレートファイルとして、ヘッダのみ記載されたCSVファイルのダウンロードをしたかった。
CSV出力の情報は多かったが、ヘッダのみの情報が少なくてちょっとつまずいたのでメモ。

モデルにメソッド追加

# CSV読み込みのテンプレートデータ作成
def csv_template
  headers = ["ユーザーアカウント", "パスワード", "パスワード(確認)", "氏名", "所属"]
  csv_data = CSV.generate(headers: headers, write_headers: true, force_quotes: true) do |csv|
    csv << []
  end
  csv_data.encode(Encoding::SJIS)    
end

csvに空のデータを入れないと、ヘッダのみ出力することはできません。

ルーティングの設定

resources :users do
  collection do
    get 'template'
  end

コントローラ追加

# CSVテンプレート
def template
  respond_to do |format|
    format.csv{ send_data User.csv_template, type: 'text/csv; charset=shift_jis', filename: "users.csv" }
  end
end

ビューにリンクを貼る

<%= link_to 'CSVテンプレート', template_users_path(format: 'csv') %>


参考:
railsにCSV形式でのダウンロード機能を追加する | dev.wan.co

Rails4 rspec3に変更したら今まで通っていたテストが失敗した。

rspecのバージョンを3.0.1に上げた後、テストを実行したら、今まで通っていたテストのほとんどが失敗した。

原因は2つあった。

1つ目は、be_trueとbe_falseが、be_truthyとbe_falseyに変更されていたからだった。

be_trueをbe_truthyに、be_falseをbe_falseyに置換した。


2つ目は、spec_helperに下記のコードを書いていたが、typeが使えなくなっていたからだった。

RSpec.configure do |config|
  config.include Devise::TestHelpers, type: :controller
end

typeを使うためには、spec\spec_helper.rbに下記を追加する。

RSpec.configure do |config|
  config.infer_spec_type_from_file_location!  # この行を追加

  config.include Devise::TestHelpers, type: :controller
end

参考:
Consider renaming `be_true` and `be_false` to `be_truthy` and `be_falsey` · Issue #283 · rspec/rspec-expectations · GitHub
RSpec 3の重要な変更 - 有頂天Ruby