LoginSignup
32
18

More than 3 years have passed since last update.

ridgepole 導入はまりどころ

Last updated at Posted at 2018-04-30

超高速チーム開発中、なのだが、
- DBスキーマの変更が多発
- migration重なりすぎて、最終形が追えない
- 仕様との突合つらい

ということで、ridgepoleに移行中です。
GWって、ちょうどよいですよね。
だいぶいい形になりそうです。

実運用までには、まだまだ宿題多数。
その過程でのはまりどころ + 残課題をここで整理して潰しこんでいきます。

導入方法は他のいい感じのページにお任せします

- 本家
- さらばmigration よろしくridgepole

dotenv 付きの config/database.yml と相性が悪い

本PRJでは、config/database.ymlにdotenvを使用しています。

で、ridgepoleをconfig/database.ymlを元に実行しようとすると、
だいぶ不親切なエラー
しかも、エラーが浅いのよね。
 verboseにしてもこれ以上の情報がなひ。

$ bundle exec ridgepole --verbose -c config/database.yml -E test --export --split --output db/schemas/Schemafile                                                                   
[ERROR] Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (111)
        /home/ec2-user/environment/base2/vendor/bundle/ruby/2.4.0/gems/mysql2-0.5.1/lib/mysql2/client.rb:90:in `connect'

見た感じは、mysql.sockまわり。
アプリケーションは元気なのに、なぜだーと戦い続けた訳です。
'/var/lib/mysql/mysql.sock' (111)
'/var/lib/mysql/mysql.sock' (2)
'/var/lib/mysql/mysql.sock' (13)

原因は、
「ridgepole読み込みのタイミングでconfig/database.yml (内のerbから.env見ている部分)が展開されない」こと。
特定までだいぶ苦戦しました。
読み込めてないなら、もっと手前でエラーだしてくれると嬉しいなぁ…。
syntaxとかとかで。

対応状況: DONE 案3 dotenv即時展開 and/or 案4 自前rake task

案1 config/database.ymlに.envを展開

庇を貸して母屋を取られた感 orz
やるならrails5.2らしく、confidential.ymlとかまで使って閉じ込めたいですね。

案2 config/database.ymlを使わずに、接続情報を直入力

$ bundle exec ridgepole --verbose -c 'ADAPTER://USERNAME:PASSWORD@HOST:PORT/SCHEME' -E development --export --split --output db/schemas/Schemafile

いやぁ、ないわ orz

案3 コマンド実行時に即時展開

dotenv自体にそれ専用のコマンドが容易されてました。
$ bundle exec dotenv -f ".env" ridgepole -c config/database.yml -E development --export --split --output db/schemas/Schemafile

案4 rake task内から間接的に

タスク経由での呼び出しを作成していたところ、
本件発生せず。
すでに envが読み込まれているから、ですね。

utf8mb4対応

ここら辺を実施するには、カラム毎のcollation/charsetあたりの管理が必要。
で、公式ドキュメント曰く

You can use the column collation by passing --enable-mysql-awesome (activerecord-mysql-awesome is required)

こちらのgem Rails5系には未対応で、うまくgem installできない
見た感じ、依存関係を修正するだけ、じゃないかと思いつつ。

対応状況: DONE Rails5系では対応済みらしい

参照: https://so-wh.at/entry/2017/06/26/233103

案1 問題発生するまで放置

採用中(ぉ
というのも、問題が再発した訳ではなく、
以下のschema定義ができているので8割くらいどうにかなってるかな、と楽観的に。

create_table "banks", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC", force: :cascade do |t|

案2 修正pullrequest投げる

案3 社内レポジトリにフォークしてうちうちに管理

デフォルトのmigration回りの機能をつぶす

とりあえず、db/migrationフォルダは削除しました。
とはいえ…
- 世の各種のgemはmigrationベースで動く
 → migrationを検知して、各開発者にridgepoleに変換させる
- rails g migration, rails db:migrateまわりのコマンドが健在
 → コマンドを潰し、警告表示
- development/test環境でのmigration(?)忘れが生じる
 → 何らかのタイミングでチェックして警告
あたりが必要かな。

対応案: 検討中(80%くらいDONE with 案4)

案1 migrationの実行だけ止める 生成は許可

 → Pending の警告が出るな。さて、どうしよう。

案2 rubocop追加して、ゆるーく警告

案3 generate modelまわりから migration生成をstop

templateまわりの設定を、軽くいじります 参照
config/application.rb

config.generators do |g|
  g.orm :active_record, migration: false      
end

ちなみに、ここら辺のgenerator回りの設定、肥大化してくるので、
個人的に、config/initialize/generator.rbに切り出しています

MyApp::Application.config.generators do |g|
  g.stylesheets false
  g.helper false
  g.decorator false
  g.orm :active_record, migration: false      
end

# Use the responders controller from the responders gem
MyApp::Application.app_generators.scaffold_controller :responders_controller

案4 Migrationのチェック機構を潰す (rack除去)

Migrationがあろうがなかろうが、サービス起動します。

config/application.rb

config.middleware.delete ActiveRecord::Migration::CheckPending

自動デプロイ

capistranoまわりのデプロイについては、いろいろドキュメントがありますね。
こことかこことか

capistranoではなく、AWS ElasticBeanstalkを使ってます。
ebextensionsまわりで管理する感じになりますね。

対応案

プロジェクトのテンプレート修正

RoRプロジェクトということで、自動でmigrationが組み込まれてるみたいですね。
そこを差し替える形になるのかな。

コマンドの引数多い

覚えられませんね。しかも、大方デフォルト設定でよいですし。
デフォルト設定用のファイルというのも見当たらない。
皆さんどうしてらっしゃるんだろう?

対応案:DONE 案1 必要分だけタスク作成

案1 rails db:xxxxx というrake taskを自作して一律導入。

ここを参考にさせていただきました。
とりあえず、apply と exportだけ作ったった
呼び出し方
$ rails db:export
$ rails db:apply RAILS_ENV=production

namespace :db do
  config_file = 'config/database.yml'
  schema_file = 'db/schemas/Schemafile'

  desc 'apply Schemafile and update schema.rb'
  task apply: :environment do
    ENV['ALLOW_DROP_TABLE'] ||= '0'
    ENV['ALLOW_REMOVE_COLUMN'] ||= '0'
    ENV['RAILS_ENV'] ||= 'development'
    task_return = `ridgepole -E #{ENV['RAILS_ENV']} --diff #{config_file} #{schema_file}`
    column_condition = task_return.include?('remove_column') && ENV['ALLOW_REMOVE_COLUMN'] == '0'
    table_condition = task_return.include?('drop_table') && ENV['ALLOW_DROP_TABLE'] == '0'
    if column_condition || table_condition
      puts '[Warning]this task contains some risks: "remove_column" or "drop_table"'
    else
      sh "ridgepole -E #{ENV['RAILS_ENV']} -c #{config_file} --apply -f #{schema_file}"
      sh 'rake db:schema:dump'
    end
  end

  desc 'write Schemafile from db'
  task :export do
    ENV['RAILS_ENV'] ||= 'development'
    sh "ridgepole -E #{ENV['RAILS_ENV']} -c #{config_file} --export --split --output #{schema_file}"
    sh 'rake db:schema:dump'
  end
end

案2 いい感じのalias作って、各自に導入さす

alias を .bash_profileあたりに突っ込む感じ。
徹底できないのが、つらみ。
変に環境依存問題で時間とられそうだなー、というわけで、こちらは棄却。

参考

32
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
18