超高速チーム開発中、なのだが、
- DBスキーマの変更が多発
- migration重なりすぎて、最終形が追えない
- 仕様との突合つらい
ということで、ridgepoleに移行中です。
GWって、ちょうどよいですよね。
だいぶいい形になりそうです。
実運用までには、まだまだ宿題多数。
その過程でのはまりどころ + 残課題をここで整理して潰しこんでいきます。
導入方法は他のいい感じのページにお任せします
例
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あたりに突っ込む感じ。
徹底できないのが、つらみ。
変に環境依存問題で時間とられそうだなー、というわけで、こちらは棄却。
参考