むかしむかし、クラウドサービスプロバイダーが存在し、進歩に追いつくことを望んでいました。 そして彼は、Rails 4.2.8からRails 5.0.2にアップグレードすることにしました。 そして、それがどのように、それが途中で落ちたのか、加速して額に当たったのか、これからどんな経験が得られたのか-猫の下で読んでください。
ほとんどの機能と問題は決して相互に関連していないため、断片的に説明します。 したがって、つまらないものや知られているものに出会ったら、次のポイントに進んでください。おそらく、もっと面白いでしょう。
ストーリーの目的:普遍的な遷移アルゴリズムはありません。見つかった情報と、Gemfileのバージョンを微調整するだけでRails 5に行くことができない理由についてのさまざまな程度の詳細を共有したいだけです。
既往歴
平均的なアプリケーションがあります:Ruby 2.2.3、数百の宝石の尾を持つ3つ、〜1500アクション、postgres、elastic、radish。 一般的に、特別なことは何もありません。 テストが90%+でカバーされていない限り。 これは、一部の最新のアプリケーションの特徴ではないようです。
最初から始める
Rails 5.2は間近に迫っていますが、メジャーバージョンの更新を急いでいる人はいません。 したがって、インターネットには、移行の機能に関する情報が必要なほど多くありません。 ここに多かれ少なかれ有益な記述があります 。 5.0および5.1のリリースがあります(ところで、まだそれらをカウントしていないのは誰ですか?)。 Rails 5にアップグレードするための基本的な手順を示すオフガイドがあります。それは良いことですが、特に更新中に落ちるgem、それらの互換性、その他の経済性に関する詳細情報が必要です。 公平に言えば、より詳細に調べれば、2組の高貴な熊手に沿って歩くことはできなかったでしょう(詳細については後述)。 したがって、以下ではガイドからのいくつかのポイント(つまり、いくつかの基本的な変更)に言及しますが、それは私たちにとって非常に重要であることが判明しました。
重大な問題の原因またはTLではなく、DR
使用する宝石の中には、Rails 5との互換性が低いか、まったく互換性がないものもあります。そのため、それらを切り取ってレールをネイティブ機能に置き換えるか、宝石を動作状態に仕上げる必要があります。 いずれにせよ、あなたはそれらを選び、質問に答える必要があります:「どのように機能しましたか?」、「それは機能しますか?」、「それを機能させるために何をしますか?」。 次に、フォーク/コントリビューション/パッチ適用を開始します。
Railsのメジャーバージョンに続くgemのメジャーバージョンの更新。したがって、gemsが提供するインターフェイス、API、およびその他のプラグインの大幅な変更。 これらのことは、大量交換および/または以前は働いていたもののカットを必要とし、食べ物を求めませんでした。
- Core_ext、みんなに愛され、嫌われている:個人使用のためのカーネルとgemのパッチ。 最も悪意のある学校は、まさにそれらのためでした。 「なぜそれがどのように機能したのか」、「そしてなぜそれを行ったのか」、「gemの新しいバージョンでは、すべてが地獄に書き直されました、何をすべきか」などの質問がたくさんあります。
宝石の更新
何かが落ちるためには、何かを更新する必要があります。 当然、rails gemとその依存関係から始める必要があります。 ここでは、1日か2日過ごすことができますが、レシピはありません。 Gemfile 、 Gemfile.lockの周りのタンバリンとのダンスがたくさんあり、プロジェクト内のすべてのかなりの半分を更新する必要があるという段階的な理解があるため、少なくとも動けなくなります。 手順は次のとおりです。
- ギャングアップ
- コンソールが起動します
- サーバーが起動します
- 少なくとも3つのアクション/リクエストが連続して実行されます。
そのままの錫
今、すべてについて。
alias_method_chainは見られています
まだ知らない人のために: prepend
を行う必要があります。 要するに:誰もが知っているinclude
に、これはクラスの前ではなくクラスの後にモジュールを追加します。 おまけとして-メソッドの有無にかかわらずsuper
を取得します。 ここで詳細と例を参照してください。
多くの新しいデフォルト設定
それらはrails app:update
を介して生成されrails app:update
。 しかし、このタスクは非常に馬鹿げており、ファイルを作成するだけです。すでにファイルの1つを持っている場合は、自分でそれを保持してください。
宝石device_async
デバイスの新しいバージョンの場合、これは不要であり、 off.manuluの数行のコードに置き換えられます。 公平に言えば、これはRails 4.2以降で機能しますが、5つのレールでは最終的にgemが機能しなくなり、すべてをActiveJobに書き換える必要があります。
宝石缶
CanCanCanに置き換える必要があります 。 CanCanのサポートは不足しており、多くの廃止予定が次々と登場しているため、Rails 5.1では問題になります。 一般的に、交換に大きな問題はないはずです。 inherited_resourcesの下でCanCanドリルを行ったため、もう少し苦労しました。
ジェムグレープスワガー
持っていた 拡張 パッチバージョン。 彼は、リクエストでAPIキーを置き換える方法を知っていました。 しかし、Swaggerの最後のメジャーバージョンでは、彼は高貴な事件を見ました。 そのため、3.0への移行後、馴染みのあるランドマークを見つけることができず、古いパッチは愚かに挿入する場所がありませんでした。 その結果、カスタムHTTPヘッダー用のドキュメント化された機能があることが判明しましたが、うまくいかず、少し密輸しなければなりませんでした 。 これですべてが機能します。
has_manyアソシエーションに無効なオブジェクトを挿入します
無効なオブジェクトの関連付けがhas_manyに挿入されると、すべてがRails 5にドロップされます(オブジェクトは永続化されて無効になり、メモリ内でのみ作成されます)。 以前は、保存が行われ、データベースの元のオブジェクトが関連付けに追加され、メモリからの変更がスキップされた(または検証がスキップされた)か、xsに何が起こったのかが深く掘り下げられていませんでした
関係の連結
彼はどこかで離婚し、もう働いていません。
バグではなく、uniqの廃止
Uniqはdistinctに置き換えられ、5.1ではReilationのuniqが最終的にカットされます。 私が理解しているように、ついに実現したのは、リレーション、配列を模倣することは機能ではなく、多くのがらくたであるということです。
宝石postgres_ext
決定的に切り抜く必要があります。 彼が行う方法を知っているのは、raw-sqlおよび/またはArelを使用して簡単に置き換えることです。 現時点では、gem自体はRails 5と互換性がありません。新しいレールで使用しようとすると、たとえばSTIクラスでcount
を呼び出す場合など、最も予期しない場所でエラーが発生しcount
。
ArgumentError: wrong number of arguments (given 1, expected 2) # /Users/username/.rvm/gems/ruby-2.3.3@gemset/gems/arel-7.1.4/lib/arel/visitors/reduce.rb:12:in `visit' # /Users/username/.rvm/gems/ruby-2.3.3@gemset/gems/postgres_ext-3.0.0/lib/postgres_ext/arel/4.1/visitors/postgresql.rb:22:in `block in
宝石simple_form
何らかの理由で、私たちと一緒に彼にはほとんど何も起こりませんでした。 彼は仕事を続けました。 include_blank
を実行し、フィールドをrequire
機能が低下しました。
ActiveRecordのその他
- ARは、(特定のクラスの)定数を条件に渡すことを誓い、定数ではなく文字列を渡すと言います。 実際、たとえば、STIを使用したテーブルでの検索の場合:
# Model.where(content_type: SharedFile) # Model.where(content_type: SharedFile.name ) # Model.where(content_type: 'SharedFile')
- すべてのモデルは、
ActiveRecord::Base
代わりにApplicationRecord
から継承する必要があります。 つまり、中間の抽象クラスが表示されます。
class ApplicationRecord < ActiveRecord::Base self.abstract_class = true end
データベース列をモデルにマッピングする原理を大幅に変更しました。 特に、これは
column_names
メソッドに適用されます。 属性などを介してユーザー定義の属性を返しなくなりました(詳細については、4〜5レールのARでこのメソッドの差分を参照してください)。attributes_to_define_after_schema_loads
の概念attributes_to_define_after_schema_loads
登場しました。 そして今、「仮想」属性に基づくロジックがあり、column_names
がすべてを返すようにしたい場合、次のようなことをする必要があります。
def self.column_names super + attributes_to_define_after_schema_loads.keys end
定数
ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES
ます。 私の知る限り、多くの人がそれを使用していましたが、今では2つのオプションがあります。手で戻すか、FALSE_VALUES
を使用するFALSE_VALUES
に切り替えることです。
- 引数を
reload
(強制リロードの場合)に渡すことはできません。 次に、特定のリレーショナルでリロードを呼び出す必要があります。 例:
first_model = Model.first first_model.has_many_relation_name.reload
has_one関連付けについても同様です:
second_model = Model.second second_model.reload_has_one_relation_name
false
ときにbefore_
コールバックを停止しfalse
-カットアウトされます。 ここで、コールバックで明示的にthrow(:abort)
させる必要があります。 ここで、これについて高貴なホリバーとMR。
raise_in_transactional_callbacks
raise_in_transactional_callbacks=
パラメーターはraise_in_transactional_callbacks=
。これは、falseが返された場合にafter_commit
/after_rollback
から実行をスローする役割をafter_commit
ます(以前は静かにログにメッセージを書き込み、例外をスローしなかった可能性があります)。 このことはRails 4で削減されましたが、書き換えに悩む人はほとんどいないようです。 今がその時であり、すぐに古い振る舞いはなくなります。
デフォルトではすべて、
belong_to
ます。 すべてを元の場所に戻すには、config.active_record.belongs_to_required_by_defaultパラメーターを使用する必要があります。
ActiveRecord::Relation#update
メソッドが登場しました。これにより、コールバックと検証を呼び出すことでRelation
を更新できます。 本質的に、これは砂糖です。データベースへの多くのクエリがあり、その中には単なるマップがあります。 MRの詳細。
- これで、副作用なく
LEFT JOIN
を作成できます。 Rails 5より前のバージョンでは、OUTER JOIN
はjoinsを介して明示的に記述でき、 includes + referenceまたは同等のeager_loadを使用できました 。 アドオンとして、指定されたすべての関係のダウンロードを取得します。これは、上記のすべての主な目的(joins
除く)がN + 1の解決に役立つためです。 現在、ActiveRecord::Relation#left_outer_joins
があります。これは、左結合だけを行い、それ以上は行いません。 詳細については、 MRにアクセスしてください。
コントローラーのパラメーター
現在、これはHashWithIndifferentAccess
ではなく、独立したクラスActionController::Parameters
であり、下位互換性のためにハッシュを模倣していますmerge
、ハッシュとして使用される場合、つまりmerge
、 update
などを行う場合、多くのことを誓います つまり、アイデアを正しく理解した場合、 params
2つの目標があります。クライアントからparams
ものを保存し、 Strong Parametersを使用してコンテンツをフィルタリングすることです。 他の変更を加えないでください。 つまり、 params
でデータを直接変更すると、独自のデータを追加するのと同じように味が悪くなります。 これらのアクション用に個別のオブジェクトをparams.to_h
か、 params.to_h
またはparams.to_unsafe_hash
を呼び出してから、以前と同じようにハッシュを処理します。
エラーによるモデルへのエラーの追加[] =
ActiveModel::Errors#[]=
Rails 5.1で見られますが、最終的にはmodel.errors.add(:name, "can't be blank")
を使用する必要model.errors.add(:name, "can't be blank")
。 もちろん、これに関するログ内のメッセージは存在します。
アレルについて少し
オブジェクト自体を転送するためにid
フィールドのArelからのeq
(および、おそらく同様の述語)で(他のフィールドではすべて問題ありません)、4レールで識別子(pk)がこのオブジェクトから引き出され、リクエストで置換されました。そして、5つのレールではこれは起こりません。 pkをプルしようとする代わりに、オブジェクトは単にNULLで置換され、「account_id = NULL」のようなものが取得されます。 例:
# Rails 4 MyModel.arel_table[:my_field].eq(MyModel.first).to_sql => "my_models"."my_field" = 1 MyModel.arel_table[:id].eq(MyModel.first).to_sql => "my_models"."id" = 1 # Rails 5 MyModel.arel_table[:my_field].eq(MyModel.first).to_sql => "my_models"."my_field" = 1 MyModel.arel_table[:id].eq(MyModel.first).to_sql => "my_models"."id" = NULL
したがって、意味を常に明示的に示すようにしてください。
skip_callbackについて
4つのレールのskip_callback(:create, :after, :my_method)
を使用すると、パラメーターを転送でき、コールバックチェーンにそのようなメソッドがなくてもクラッシュしません。5つのレールでは、次のメソッドが見つからなかった場合、同じメソッドが実行されますスキップする必要があります。 したがって、奇妙な転倒が発生する可能性があり、「少年はいたのか?」を理解するために、産業考古学を掘り下げる必要があります。
レンダリングの小さな革命
変更:text
mime_type
を明示的に示す:text
およびその他の形式。 置換:nothing
:head
など つまり、彼らはその起源に戻り、名前を本質に近づけ、主婦が理解するのにアクセスできないようにします。
テスト実行の順序を変更する
現在、デフォルトの実行順序は:random
です。 テストが実行シーケンスに依存している場合、これはあまり良くありませんが、古い動作を返すのは非常に簡単です:
Rails.application.configure do config.active_support.test_order = :sorted end
オブザーバー
今まで(またはすでに)5つのレールでそれらをサポートしている人はいません。 元のオブザーバーは4本のレールで停止しました。 ウィザードでは、5のサポートを宣言しましたが、何も機能しません。 5レールのオブザーバーに代わる日本人がいます(コピーアンドペーストやブランド変更に非常に似ています)が、これも機能しません。 最善の方法は、ネイティブのARコールバックを使用することです。
ActiveRecordのバグ
カップルを見つけました:
- 1つ目は
ActiveRecord::Associations::CollectionProxy
に関する古いuniq
です。これは有名であることが判明し、5.1で既に修正されています。 - 2つ目は新しく、より興味深いものです。ARモデルの属性を暗黙的にフリーズするにはどうすればよいですか。
宝石の肩マッチャー
それを3.1.1に更新し、多くの異なる小さなものを得ました:
- 大文字と小文字を区別するデフォルトの
email
チェックがありました。 - スコープチェックがより厳しくなりました:モデルの
uniqueness
ためにscope
が指定されている場合でも、以前にshould validate_uniqueness_of(:name)
が渡されると、テストがクラッシュし、明示的に指定するshould validate_uniqueness_of(:name).scoped_to(:vendor_id)
ますshould validate_uniqueness_of(:name).scoped_to(:vendor_id)
; - 直列化された属性をチェックし、
should serialize(:metadata).as(Hash)
ドロップをcast_type
でcast_type
するcast_type
ます。 - 以前、
allow_value('foo', 'bar', 'baz')
メソッドallow_value('foo', 'bar', 'baz')
は渡された引数から最初の値のみを取得していましたが、現在は修正され、すべてを取得するようになりました。
移行
インデックス名の形成方法と、後方互換性を完全に破った他のいくつかの方法を変更しました。 したがって、すべての移行に対して、それらが作成されたバージョンを明確に示す必要があります。 クラスパラメーターを使用して指定します。
class OldMigrationName < ActiveRecord::Migration[4.2] ... end class NewMigrationName < ActiveRecord::Migration[5.0] ... end
また、 references
のオプションでforeign_key
を指定することもできました。 そして、ジェネレーターのデフォルト設定を少し変更しました :デフォルトでは、pk(このid)は整数ではなくuuidになります。
何らかの理由で、移行内のパターンの定義にも問題がありました。 つまり、フォームの一部で:
class SomeMigration < ActiveRecord::Migration class StubForModel < ActiveRecord::Base has_one :something end def up StubForModel.destroy_all end def down # do nothing end end
誰かがBase
見つけられないと誓っています。 理由がわかるまで、注意してください。 解決方法-説明を更新します。
コントローラー内のコールバックのシーケンス
Rails 4でのcsrf
トークン(偽造からの保護)のチェックは常に上がり、コントローラーの最初のコールバックによって行われました。 Rails 5では、どこにも上がらず、定義された場所に従って実行されprepend: true
。上げる必要がある場合は、 prepend: true
明示的に指定する必要がありprepend: true
。
すべては問題ありませんが、最初に与えられたガイドを注意深く読んだようには見えませんでした。 認証が失敗しました。 デバイス全体を掘り起こし、ほとんど魔法を信じていました。 しかし、最初はデバイスがパラメータからトークンを正常に認証して切り取り、その後偽造から保護され、湾曲した(実際に欠落している)トークンに非常に怒っていることが判明しました。
マンキパッチ
「他の人への彼の例は科学です...」
- コントローラーのテストでは、Cookie領域の深すぎるスタックレベルからクラッシュします 。 彼らはいくつかの明るい頭を壊し、2回目はRequestStoreに関連するマンキャッチを発掘するまで、ほとんど魔法を信じていました。
- 上記のcsrfトークンのケースは、
飲んだ認証パッチ。 実際、csrf
トークンの2つのチェックがありましたcsrf
つはデバイスの前、もう1つは後です。 これは、問題の検索の簡素化にはまったく貢献しませんでした。 - 以前、前述のCanCanにもパッチが適用され、快適なものはほとんどありませんでした。
- 独自の完成した
ActiveRecord::Type
がありましたが、これは新しいレールでほとんど掘り下げられました: あり 、 そうなり、ActiveModel
に転送されました。 - 説明できることは他にもたくさんありますが、それらは新しいレールへの移行にほとんど参加しなかったため、後で使用します。
なぜ私はこれをすべてやっているのですか: core_ext
はすべきではありません。 絶対に。 そして、新しいレールへの移行は、それらから始めて、できる限りカットして、非常にうるさい外観で他のすべてを見て、この拡張の出現前の歴史(間違いなく非常にまだらになっている)を覚えておくための大きな理由です。 そのため、移行中にいつ落ちるかを理解するのがはるかに簡単になります。
Rubyバージョンのアップグレード
正直なところ、私たちは習得していません。 2.2.3の後、2.4.0を強力にスタックして、私たちは未知のゴミの束をすくい取り、2つの段階に進むことを決めました:最初に、Ruby 2.3.3、これは非常に革命的なものはなく、新しいレールへの移行です。 そして-ルビーを更新します。 したがって、これまでのところ、新しいルビーについては何も言えません。 gemのネイティブ拡張をコンパイルした場合、移行の問題のほとんどは回避され、深刻な障害はないという経験豊富な仲間の意見がない限り。
マジック(時間と欲求があるかどうかを考えるタスク)
新しいレールへの移行に関係なく、移行中に発掘されて機能したはずの奇妙なコードに過ぎませんが、そうすべきではありません(ARクラスの3つのファイルの要約)。
class Base TYPES = {first: First, second: Second} end class First < Base; end class Second < Base; end
このことは、このジャンルのすべての法律により、機能しません(ただし、一般的にRails 4/5のクリーンプロジェクトでは機能しません)。 相続人のいずれかにアクセスすると、自動ロードはクラスの周期的なロードに入り、クラッシュします。 最初に基本クラスを使用し、次に相続人を使用する場合、すべてが正常です。 しかし、何らかの理由で、Rails 4では機能しましたが、Rails 5では落ちましたが、他のすべてよりも早くBase
をダウンロードする明示的な呼び出しを見つけることができず、自動ロードに関連するものはまったく触れませんでした。 他の誰かがそれがどのように機能するか、またはRails 5の自動ロードに何が起こったのかを知っているなら、私に知らせてください。
終わり
読んでくれてありがとう。 少なくとも何かがあなたの役に立つことを願っています(または既に便利になっていること)、そして移行のための時間を少なくとも少しは節約しました。
トピックに関するあなたの知識と経験ではなく、コメントで共有することをheしないでください。