問題
転職活動用のポートフォリオをAWSでのデプロイが完了したところ。
本番環境でchart.jsで作ったグラフを表示しようとしたところ、以下のエラーが表示された。
エラー
Mysql2::Error:Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'pfc-master_production.posts.created_at' which ins not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by: SELECT `posts`.`created_at` FROM `posts` WHERE `posts`.`user_id = 2 GROUP BY date(created)
関連するソースコード
charts_controller.rb
class ChartsController < ApplicationController
def index
# カロリー
@sampleuser = User.find_by(id: 2)
if user_signed_in?
# 日付ごとで分けてカロリー合計を算出
sum_calorie = current_user.posts.group("date(created_at)").sum(:calorie)
# 日付ごとのカロリー合計がハッシュの形なので値を取得して配列に入れて変数に代入
array_calorie = sum_calorie.values
else
sum_calorie = @sampleuser.posts.group("date(created_at)").sum(:calorie)
array_calorie = sum_calorie.values
end
# gonを使ってデータをjs側に渡す
gon.data = []
# mapメソッドで日付ごとのカロリー合計を1つずつ取り出す
# mapメソッドの使い方 → 配列変数.map {|変数名| 具体的な処理 }
gon.data = array_calorie.map{ |calorie| calorie}
binding.pry
if user_signed_in?
# 日付ごとにまとめてそのうちcreated_atカラムだけ取得。配列の形で格納されている
dates_calorie = current_user.posts.group("date(created_at)").select(:created_at)
else
dates_calorie = @sampleuser.posts.group("date(created_at)").select(:created_at)
end
gon.date = []
@dates = dates_calorie.map{ |dates| dates.created_at} ⬅️この部分でエラーが出た
# each文で日付の表記を1つずつ取り出して変える
@dates.each do |a|
gon.date << a.strftime("%Y年%m月%d日")
end
binding.pry
# 体重
if user_signed_in?
gon.weight = current_user.posts.group("date(created_at)").select(:weight).map{ |weight| weight[:weight]}
else
gon.weight = @sampleuser.posts.group("date(created_at)").select(:weight).map{ |weight| weight[:weight]}
end
end
end
解決手順
MySQLの設定ファイルであるmy.cnf
を編集する。
vi /etc/my.cnf
でmy.cnf
を開いて
下記のコードを追加した。
[mysqld]
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
my.cnf
は読み取り専用ファイルなので、通常vimを上書き保存するshift+ZZ
や:wq!
では上書き保存できなかった。
読み取り専用ファイルを上書き保存するには下記を入力して
:w !sudo tee %
そのうえで下記でvimファイルを閉じる。
:q!
my.cnf
を編集し、MySQLの設定を変更したら、変更点を反映させるためにMySQLを再起動する。
service mysqld restart
なぜ解決できたのか
今回のエラー原因
MySQl5.7からデフォルトのままだとsql_modeでONLY_FULL_GROUP_BYが設定されるようになったため、一意にできていない場合にこのエラーになるそうです。
きちんと対応する方法としてはSQLをきちんと一意に特定できるように、GroupBy句に取得するカラムを指定したり、MAXやMIN、SUMなどで一意になるように修正する必要があります。
今回エラーが出たのはcharts_controller.rb
の下記の部分だった。
@dates = dates_calorie.map{ |dates| dates.created_at}
変数dates_calorie
には下記のように、current_userの投稿を日付ごとにまとめて、created_atカラムを取得し配列に入れていったものが入っている。
dates_calorie = current_user.posts.group("date(created_at)").select(:created_at)
同日に複数の投稿がある場合、.group("date(created_at)")
で1つにまとめているので、同じ日付が複数存在することはあり得ず、一意になっているはずなので、なぜ「一意になるように修正しなさい」と言われるのかわからない。
実際、ローカル環境では問題なく動いているのに。
ONLY_FULL_GROUP_BY というデフォルトの自動設定をOFFにしてしまえばエラーが出なくなるという参考記事を見つけ、それを実行したところ、冒頭のエラーは表示されなくなった。