Herokuへpushするときに「Failed to install gems via Bundler.」と「NoMethodError: undefined method `factory_bot’ for #<Rails::Application::Configuration:0x0000556cf580a310>」が出た

まさかこんなにハマるとは思いませんでした...。
備忘録としてハマったエラーの対処法をまとめます。


流れと結論

Herokuへpushする際に2つのエラーに遭遇しました。
1.「Failed to install gems via Bundler.」

→  ローカルのbundlerのバージョンをherokuと一致させる
→  Gemfile.lockにplatform の追加



2.「NoMethodError: undefined method `factory_bot’ for #

→  config/application.rb の config.factory_bot.definition_file_paths = [“spec/factories”] を削除


これによって無事Herokuにpushできました。



1つ目のエラー解決方法

$git push heroku main を実行したところ以下のようなエラーが発生。

Enumerating objects: 839, done.
Counting objects: 100% (839/839), done.
Delta compression using up to 8 threads
Compressing objects: 100% (780/780), done.
Writing objects: 100% (839/839), 405.51 KiB | 7.37 MiB/s, done.
Total 839 (delta 438), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote: 
remote: -----> Building on the Heroku-20 stack
remote: -----> Determining which buildpack to use for this app
remote:  !     Warning: Multiple default buildpacks reported the ability to handle this app. The first buildpack in the list below will be used.
remote:                         Detected buildpacks: Ruby,Node.j
remote:                         See https://devcenter.heroku.com/articles/buildpacks#buildpack-detect-order
remote: -----> Ruby app detected
remote: -----> Installing bundler 2.2.11
remote: -----> Removing BUNDLED WITH version in the Gemfile.lock
remote: -----> Compiling Ruby/Rails
remote: -----> Using Ruby version: ruby-2.7.2
remote: -----> Installing dependencies using bundler 2.2.11
remote:        Running: BUNDLE_WITHOUT='development:test' BUNDLE_PATH=vendor/bundle BUNDLE_BIN=vendor/bundle/bin BUNDLE_DEPLOYMENT=1 bundle install -j4
remote:        Fetching gem metadata from https://rubygems.org/............
remote:        Your bundle is locked to msgpack (1.4.1), but that version could not be found in
remote:        any of the sources listed in your Gemfile. If you haven't changed sources, that
remote:        means the author of msgpack (1.4.1) has removed it. You'll need to update your
remote:        bundle to a version other than msgpack (1.4.1) that hasn't been removed in order
remote:        to install.
remote:        Bundler Output: Fetching gem metadata from https://rubygems.org/............
remote:        Your bundle is locked to msgpack (1.4.1), but that version could not be found in
remote:        any of the sources listed in your Gemfile. If you haven't changed sources, that
remote:        means the author of msgpack (1.4.1) has removed it. You'll need to update your
remote:        bundle to a version other than msgpack (1.4.1) that hasn't been removed in order
remote:        to install.
remote: 
remote:  !
remote:  !     Failed to install gems via Bundler.
remote:  !
remote:  !     Push rejected, failed to compile Ruby app.
remote: 
remote:  !     Push failed
remote: Verifying deploy...
remote: 
remote: !       Push rejected to score-log.
remote: 
To https://git.heroku.com/score-log.git
 ! [remote rejected] HEAD -> main (pre-receive hook declined)
error: failed to push some refs to 'https://git.heroku.com/score-log.git'

Herokuでのbundlerが2.2.11となっているがローカルのbundlerは2.1.4となっていました。
ローカルのbundlerのバージョンを2.2.11とするために以下の記事に記載されていることをそのまま実行しました。


yumishin.com


これでエラー解決と思いきや、またも同じ「Failed to install gems via Bundler.」のエラー。
いろいろ調べてみると、一部の Mac では Gemfile.lock の PLATFORM が不足しているためにHerokuへのpush時にエラーが出るとのこと。

$ bundle lock --add-platform ruby
$ bundle lock --add-platform x86_64-linux
$ bundle install


ここに関してはあまり理解できていません......



2つ目のエラー解決方法

これでやっとHerokuへpushできると思ったのですが、またエラーに遭遇しました。

remote:  !     Could not detect rake tasks
remote:  !     ensure you can run `$ bundle exec rake -P` against your app
remote:  !     and using the production group of your Gemfile.
remote:  !     rake aborted!
remote:  !     NoMethodError: undefined method `factory_bot' for #<Rails::Application::Configuration:0x0000559ccfd5f860>


factory_botが未定義と出ています。
Gemfileやfactory_bot周辺を調べましたが、原因が分からずメンターさんに相談しました。

config/application.rbに

config.factory_bot.definition_file_paths = [“spec/factories”] 

が追加されていることが原因ではないかとのこと。



以前factory_bot導入時のエラー対処で上記をconfig/application.rbに追加していました。
gem 'factory_bot_rails' をテスト環境にのみ入れているにも関わらず、config/appcliation.rbに config.factory_bot.definition_file_paths = [“spec/factories”]  を追加したことで本番環境にもfactory_botを入ってしまっていたようです。
そのためpushする際にfactory_botが未定義となっていました。

上記の記述を削除することで無事Herokuへpushすることができました。

config.factory_bot.definition_file_paths = [“spec/factories”] 

私の場合はこの記述は不要でしたが、必要であれば
・config/environments/development.rb
・config/environments/test.rb
の2箇所に追加すればいいようです。

Rails6での flatpickr 導入

Rails6 から Webpacker が導入されたため、flatpickr の導入がこれまでと異なり苦戦したので備忘録として記録します。


下記の記事を参考に導入しました。
dzone.com

flatpickrの導入

1.Yarn に必要なライブラリをターミナルで追加

$ yarn add bootstrap jquery popper.js flatpickr

2.jQuery を使用するためのコードを追記
config/webpack/environment.jsに記述

const { environment } = require('@rails/webpacker')

const webpack = require('webpack')
environment.plugins.append('Provide', new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery'
}))

module.exports = environment

3.CSSでWebpackerを扱う
app/views/layouts/application.html.erbに以下の記述を追加

<!--  stylesheet_link_tag の行の下に記述する -->
<%= stylesheet_pack_tag "application", media: "all", "data-turbolinks-track": "reload" %>

javascriptディレクトリ内にCSS用のファイルを作成

mkdir app/javascript/stylesheets
touch app/javascript/stylesheets/application.scss

作成したapp/javascript/stylesheets/application.scssファイルに次を追加

@import "flatpickr/dist/flatpickr.css";

4.JavaScript ファイルを読み
app/javascript/packs/application.js に以下のコードを追記

require("flatpickr")
import flatpickr from "flatpickr";
document.addEventListener("turbolinks:load", () => {
  flatpickr("[class='flatpickr']", { })
})

// stylesheets
require("../stylesheets/application.scss")
})


あとはclassに 'flatpickr' を指定すば表示できるはずです。

      <%= form_with model: @log, local: true do |f| %>
        <%= hidden_field_tag :score_id, @score.id %>
        <div>
          <%= f.text_area :content, placeholder: "練習記録", class: "text-box" %>
        </div>
        <div>
          <%= f.text_field :start_time, placeholder: "日付を選択", class: 'flatpickr' %>
          <%= f.submit "記録する", class: "record-btn" %>
        </div>
      <% end %>

おまけ

flatpickrは様々なカスタマイズが可能です。
今回は以下のようにカスタマイズを行いました。
スマートフォンでも使用
・日付の選択を今日まで可能に

document.addEventListener("turbolinks:load", () => {
  const TODAY = new Date(new Date().setHours(0, 0, 0, 0))
  flatpickr("[class='flatpickr']", {
    // スマートフォンでもカレンダーに「flatpickr」を使用
    disableMobile: true,
    // 今日までを選択可能
    maxDate: TODAY
  })
})


f:id:alv5:20210307113831j:plain

PostgreSQLでテーブルの型をintegerにしたらPG::DatatypeMismatch: ERRORで失敗した

テーブルでstring型 を integer型 に変更しようとしたらマイグレーションができませんでした。

== 20210213101041 ChangeDatatypeStatusOfScores: migrating =====================
-- change_column(:scores, :status, :integer)
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:

PG::DatatypeMismatch: ERROR:  column "status" cannot be cast automatically to type integer
HINT:  You might need to specify "USING status::integer".


エラー文には
「statusカラムは自動的に整数型にできないよ」
「ヒント:USING句を使用しましょう」
というようなことが書かれています。
ヒントのまんま"USING status::integer"を使ってみましたが、マイグレーションできませんでした...


調べてみたところ下記のように記述するようです。

変更したいデータ型 CAST(カラム名 AS 変更したいデータ型)

CAST 関数は引数に指定した値(カラム名)を別のデータ型に変換するために使用します。


class ChangeDatatypeStatusOfScores < ActiveRecord::Migration[6.0]
  def change
 #  change_column :scores, :status, :integer    (変更前)
    change_column :scores, :status, "integer USING CAST(status AS integer)"
  end
end

これでデータ型の変更ができました。

【Rails】ログイン機能(devise)の導入方法

1.Gemfileに 「gem 'devise'」を追記

gem 'devise'

記述箇所によって開発環境のみやテスト環境のみで使えるように指定もできる。
どの環境でも使えるようにするには group :development, :test do よりも上に記述する。

ターミナルで以下のコマンドを実行してgemをインストール。

$ bundle install



2.設定ファイルを作成
deviseはGemのインストールをするだけでは使用できない。そのため devise 専用のコマンドを利用して設定ファイルを作成。
ターミナルで以下のコマンドを実行。

$ rails g devise:install



3.モデルの作成
devise を使用する際のモデルの作成。
通常の方法 rails g model ではなく、devise 専用のコマンドを使用することでログイン機能に対応したモデルを作成することができる。
ターミナルで以下のコマンドを実行。

$ rails g devise User



4.マイグレーションを実行
マイグレーションを実行しテーブルを作成。

$ db:migrate



5.viewファイルを作成
今のままだと views ディレクトリの中にファイルが存在しないのでカスタマイズができない。
devise 専用のコマンドを利用してビューファイルを生成する。

$ rails g devise:i18n:views

まとめ

Gemファイルに「gem 'devise'」を追記

$ bundle install

$ rails g devise:install

$ rails g devise User

$rake db:migrate

$ rails g devise:views

【Rails】カラムの追加・編集・削除

共同開発でカラムの削除が必要になったので、追加・変更・削除の方法についてまとめました。


すでに実行済みのマイグレーションファイルは修正や上書きをすることはできないので、変更を加える為に別のマイグレーションファイルを作成し実行する必要があります。

カラムの追加

ターミナルで以下のコマンドを実行しマイグレーションファイルを作成。

$ rails g migration add_カラム名_to_テーブル名  カラム名:型


マイグレーションファイル

class AddTitleToTexts < ActiveRecord::Migration[6.0]
  def change
    add_column :texts, :title, :string
  end
end

rails db:migrate でマイグレーションを実行。

カラムの編集

ターミナルで以下のコマンドを実行しマイグレーションファイルを作成。

$rails g migration rename_変更前のカラム名_column_to_テーブル名


マイグレーションファイルのchangeメソッドの中に以下を記述する。

rename_column :テーブル名, :変更前の名前, :変更後の名前


マイグレーションファイル

class RenameTitleColumnToTexts < ActiveRecord::Migration[6.0]
  def change
    rename_column :texts, :title, :song_title
  end
end

rails db:migrate でマイグレーションを実行。

カラムの削除

ターミナルで以下のコマンドを実行しマイグレーションファイルを作成。

$ rails g migration remove_カラム名_from_テーブル名 カラム名:型


マイグレーションファイル

class RemoveSongTitleFromTexts < ActiveRecord::Migration[6.0]
  def change
    remove_column :texts, :song_title, :string
  end
end

rails db:migrate でマイグレーションを実行。

まとめ

・テーブルの編集をする際には、その都度マイグレーションファイルを作成する。
マイグレーションファイルを作成した後には必ず「rails db:migrate」を実行する。