アクションテキストで既存のテキストフィールドを変換する方法 - Ruby on Rails


最近、Rails アプリケーションで一部のプレーン テキストをリッチ テキストに変換するタスクを割り当てられました.とても簡単に聞こえると思いますが、必要なのは Action Text をインストールし、問題のモデルを変更し、プレーン テキストをリッチ テキストに変換するための簡単な移行を作成するだけです.そんなに早くない.

移行を書き始めるまで、すべてが順調に進んでいました.ご存じないかもしれませんが、Action Text はモデルと同じデータベース テーブルにリッチ テキストを保存しません.代わりに、多態的な関係を作成します. Action Text は、インストール時に新しいテーブルを作成するための移行も作成します.残念ながら、テキストの変換は、モデルをリファクタリングして「has_rich_text」タイプのフィールドを持つようにするよりも少し複雑になります.ただし、私たちのモデルにはこれが必要なので、先に進んで今すぐ追加しましょう.

models/post.rb

class Post < ApplicationRecord
  has_rich_text :body
end


Felicián Hoppál と、この issue に対する彼らのコメントに感謝します.素晴らしい出発点と簡単な解決策です.唯一の問題は、ロールバックしようとするとこの移行が失敗することです.失敗する理由は、「post.old_body」列が存在しないためです.恐れる必要はありませんが、移行で別々の up メソッドと down メソッドを記述することで、この問題を克服できます.

example from github issue

class MigratePostContentToActionText < ActiveRecord::Migration[6.0]
  include ActionView::Helpers::TextHelper
  def change
    rename_column :posts, :body, :old_body
    Post.all.each do |post|
      post.update_attribute(:body, simple_format(post.old_body))
    end
    remove_column :posts, :old_body
  end
end


それでは、移行を作成し、Action Text から Text Helper をインポートしましょう.

rails g migration ConvertPostBodyToRichText


これで、テキスト ヘルパーをインポートして、プレーン テキストをリッチ テキストに変換できるようになりました.

20211229035004_convert_post_body_to_rich_text.rb

class ConvertPostBodyToRichText < ActiveRecord::Migration[6.1]
  include ActionView::Helpers::TextHelper
end


これで、移行の up メソッドの作業を開始できます.まず、変換したい列の名前を別の名前に変更します.これにより、アクション テキスト テーブルとの関係を作成/関連付けることができます.

20211229035004_convert_post_body_to_rich_text.rb

class ConvertPostBodyToRichText < ActiveRecord::Migration[6.1]
  include ActionView::Helpers::TextHelper
  def up
    rename_column :posts, :body, :old_body
  end
end


ここで、すべての投稿をループして、Action Text のテキスト ヘルパーを使用してリッチ テキストに変換します.

20211229035004_convert_post_body_to_rich_text.rb

class ConvertPostBodyToRichText < ActiveRecord::Migration[6.1]
  include ActionView::Helpers::TextHelper
  def up
    rename_column :posts, :body, :old_body
    Post.all.each do |post|
      post.update_attribute(:body, simple_format(post.old_body))
    end
  end
end


最後に、名前を変更した列はもう必要ないので削除します.

20211229035004_convert_post_body_to_rich_text.rb

class ConvertPostBodyToRichText < ActiveRecord::Migration[6.1]
  include ActionView::Helpers::TextHelper
  def up
    rename_column :posts, :body, :old_body
    Post.all.each do |post|
      post.update_attribute(:body, simple_format(post.old_body))
    end
    remove_column :posts, :old_body, :text
  end
end


up メソッドはこれで終了し、down メソッドに取り組むことができます.ロールバック時に発生するエラーは、名前が変更された古い列はもう存在しないため、未定義のメソッド エラーです.したがって、down メソッドで最初に行うことは、その列を作成/追加することです.

20211229035004_convert_post_body_to_rich_text.rb

class ConvertPostBodyToRichText < ActiveRecord::Migration[6.1]
  include ActionView::Helpers::TextHelper
  def up
    rename_column :posts, :body, :old_body
    Post.all.each do |post|
      post.update_attribute(:body, simple_format(post.old_body))
    end
  end

  def down
    add_column :posts, :old_body, :text
  end
end


ロールバック中にテキストを保存する新しい列を作成したので、すべての投稿をループして、リッチ テキストをプレーン テキストに変換しましょう. Action Text テーブルの関連する行も削除する必要があります.

20211229035004_convert_post_body_to_rich_text.rb

class ConvertPostBodyToRichText < ActiveRecord::Migration[6.1]
  include ActionView::Helpers::TextHelper
  def up
    rename_column :posts, :body, :old_body
    Post.all.each do |post|
      post.update_attribute(:body, simple_format(post.old_body))
    end
  end

  def down
    add_column :posts, :old_body, :text
    Post.all.each do |post|
      post.update_attribute(:old_body, post.body.to_plain_text)
      post.body.delete
    end
  end
end


最後に、データベース列の名前を元の名前に戻します.

20211229035004_convert_post_body_to_rich_text.rb

class ConvertPostBodyToRichText < ActiveRecord::Migration[6.1]
  include ActionView::Helpers::TextHelper
  def up
    rename_column :posts, :body, :old_body
    Post.all.each do |post|
      post.update_attribute(:body, simple_format(post.old_body))
    end
  end

  def down
    add_column :posts, :old_body, :text
    Post.all.each do |post|
      post.update_attribute(:old_body, post.body.to_plain_text)
      post.body.delete
    end
    rename_column :posts, :old_body, :body
  end
end


最後に、移行を実行し、必要に応じて安全にロールバックし、自信を持って本番環境にデプロイできます.安全のために、新しい移行を実行する前に、常にデータベースのバックアップを作成する必要があります. 😊