Rails4 3階層のincludesの指定

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

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

group → user → department


下記のように書いてもうまくいかなかった

# @groups = Group.order(:id)

@groups = Group.order(:id).
                includes(:user, :department)


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

# @groups = Group.order(:id)

@groups = Group.order(:id).
                includes({user: :department})


参考:
Ruby on Railsあれこれ/findメソッドの:includeオプションの書き方 - 笑猫酒家
N+1問題の対策のため、「Bullet」をインストール - ayaketanのプログラミング勉強日記

Rails4 where句をnotで否定する

私は今まで、点数がある点数以外のときというスコープを下記のように書いていました。

scope :score_is_not, ->(score) {where("score != ?", score)}

いまさらですが、Rails4では、where句をnotで否定できるようです。

scope :score_is_not, ->(score) {where.not(score: score)}

もちろん、通常のActiveRecordでもnotは使えます。

Test.where.not(score: 0)
# Test.where("score != 0")

また、INでもnotは使えるようです。

Test.where.not(score: [0, 100])
# Test.where("score NOT IN (0, 100)")


参考:
#400 What's New in Rails 4 - RailsCasts
Ruby on Rails で NOT IN な SQL をかく。 - そんなこと覚えてない

Rails4 rspecとFactoryGirlを用いたdeviseでサインインした状態でのコントローラのテスト

サインインをdeviseを用いて実装している。
サインイン必須のコントローラのテストをおこなうときに、サインイン状態を作るのに少し手間取ったのでメモ。


spec\spec_helper.rbに下記のように記載

RSpec.configure do |config|
  … 
  config.include Devise::TestHelpers, type: :controller # これを追加
end


spec\factories\user.rbに下記のように記載

FactoryGirl.define do
  factory :user do
    email "user@test.com"
    password "userpassword"
    password_confirmation "userpassword"
  end
end


コントローラのテストでは、下記のようにサインインやサインアウトをおこなう

before do
  # ユーザー作成
  @user = create(:user)
    
  # サインイン
  sign_in @user
end
  
after do
  # サインアウト
  sign_out @user
end


参考:
plataformatec/devise · GitHub
Railsのユーザ認証deviseを用いた簡単かつ突っ込んだ実装 - ema25の日記

Rails4 simplecovでテストカバレッジを調べる

specでテストを書いていますが、すべてのテストがかけているか不安だったので、カバレッジを調べることにした。

simplecovというgemを使うといいようだ。

Gemfileに次のように追記し、bundle install

# カバレッジ
gem "simplecov", require: false, group: :test

spec/spec_helperに下記を追記

# カバレッジを計測
require "simplecov"
SimpleCov.start "rails"

あとは、いつも通りテストを実行すれば、coverage/index.htmlに結果が出力されます。

参考:
colszowka/simplecov · GitHub
Rails/Ruby - テストカバレッジを調べる simplecov - そういうことだったんですね

Rails4 flashのメッセージが2回表示される

flashに設定したメッセージが2回表示されて困ったのでメモ。

下記のようにflashにalertを設定し、newを再表示していた。

flash[:alert] = "登録に失敗しました。"
render action: 'new'

登録画面で登録ボタンを押下すると、正常にメッセージが表示されたが、再度登録画面を表示すると、また同じメッセージが表示されてしまった。もう一度登録画面を表示すると、メッセージは表示されなかった。


正しくは、下記のように記載しなければいけなかったようだ。

flash.now[:alert] = "登録に失敗しました。"
render action: 'new'


flash.nowとflashでは動作が異なるようだ。

flash.now
現在のリクエストでのみ有効なメッセージを設定する。
現在のリクエストが終了した時点で、自動的にメッセージは削除される。
renderで表示する画面にメッセージを表示したい場合に用いる。

flash
次のリクエストまで有効なメッセージを設定する。
次のリクエストが終了した時点で、自動的にメッセージは削除される。
redirect_toした先の画面でメッセージを表示したい場合に用いる。


私はrenderでnewを再表示していたのに、flashを使っていたため、期待していた画面の1つ先の画面にまでメッセージが表示されていたようだ。


参考:
[Rails] flash.now[:notice]とflash[:notice]の違い - 拝啓、シーシュポス

Rails4 Chart.jsでレーダーチャートの背景色をなくす

レーダーチャートで3つのデータを比較したかった。

下記のように記載していたが、背景色があると、見にくいと感じました。

var radarChartData = {
  labels: <%= @labels.html_safe %>,
  datasets: [
    {
      fillColor: "rgba(151,187,205,0.5)", // 線で囲まれた部分の色
      strokeColor: "rgba(151,187,205,1)", // 線の色
      pointColor: "rgba(151,187,205,1)",  // 点の色
      pointStrokeColor: "#fff",           // 点を囲む線の色
      data: <%= @data1 %>
    },
    {
      fillColor: "rgba(255,146,180,0.5)", // 線で囲まれた部分の色
      strokeColor: "rgba(255,146,180,1)", // 線の色
      pointColor: "rgba(255,146,180,1)",  // 点の色
      pointStrokeColor: "#fff",           // 点を囲む線の色
      data: <%= @data2 %>
    },
    {
      fillColor: "rgba(174,255,132,0.5)", // 線で囲まれた部分の色
      strokeColor: "rgba(174,255,132,1)", // 線の色
      pointColor: "rgba(174,255,132,1)",  // 点の色
      pointStrokeColor: "#fff",           // 点を囲む線の色
      data: <%= @data3 %>
    }
  ]
};

色が重なって、なんだか見にくい気がする。
f:id:ayaketan:20140415120246p:plain


fillColorの行を削除してみたが、うまくいかなかった。
そこで、背景色に白の透明を指定してみたらうまくいった。

var radarChartData = {
  labels: <%= @labels.html_safe %>,
  datasets: [
    {
      fillColor: "rgba(255,255,255,0)",   // 線で囲まれた部分の色
      strokeColor: "rgba(151,187,205,1)", // 線の色
      pointColor: "rgba(151,187,205,1)",  // 点の色
      pointStrokeColor: "#fff",           // 点を囲む線の色
      data: <%= @data1%>
    },
    {
      fillColor: "rgba(255,255,255,0)",   // 線で囲まれた部分の色
      strokeColor: "rgba(255,146,180,1)", // 線の色
      pointColor: "rgba(255,146,180,1)",  // 点の色
      pointStrokeColor: "#fff",           // 点を囲む線の色
      data: <%= @data2 %>
    },
    {
      fillColor: "rgba(255,255,255,0)",   // 線で囲まれた部分の色
      strokeColor: "rgba(174,255,132,1)", // 線の色
      pointColor: "rgba(174,255,132,1)",  // 点の色
      pointStrokeColor: "#fff",           // 点を囲む線の色
      data: <%= @data3  %>
    }
  ]
};

背景色がなくなり、線だけのレーダーチャートになった。
f:id:ayaketan:20140415120543p:plain


関連:
Rails4 Chart.jsでレーダーチャートを表示する - ayaketanのプログラミング勉強日記

印刷で改ページを指定する(PDF出力対応)

PDF出力時の改ページを指定したかった。
印刷で改ページを指定するのと同じ方法で対処できたのでメモ。


CSSで印刷時の改ページの位置を指定できるようだ。

page-break-before 要素の直前の改ページを制御
page-break-after 要素の直後の改ページを制御

制御方法は次の3種類

auto 制御しない (初期値)
always 直後で改ページさせる
avoid 直後の改ページを禁止


私は、要素の直前で改ページを指定したかったので、CSSに下記のように記載した。

.new_page {
  page-break-before: always;
}

item毎に改ページをしたかったので、itemのタイトルに改ページを指定した。

<h2 class="new_page"><%= item.title %></h2>

heroku上でPDF出力した際に、正しく改ページがされることを確認した。


参考:
スタイルシート[CSS]/ページ全般/印刷時の改ページ部分を指定する - TAG index Webサイト
Rails4 wicked_pdfでPDF出力 ※windows未対応 - ayaketanのプログラミング勉強日記