バヅクリCTOの合原です。
今回、非エンジニアからの依頼で、「LSEP」という記号?文字?の除去作業をシュッと行ったので、まとめたいと思います。
前提
当社バヅクリでは、下記のように、オンラインで、
チームビルディングや研修を目的としてオリジナルのプログラムを提供しています。
とても、とても簡単に説明すると、、、
契約企業から特定のプログラムでのイベント開催の希望が発生すると、
アプリケーション上では、プログラムデータからイベントデータを自動生成しています。
プログラム、イベントそれぞれのデータについてCRUD処理が存在します。
通常企画チームにて、プログラムの入稿や更新、運営担当によるイベントデータの更新などが適宜行われています。
調査
さて、今回、見たこともない「LSEP」なるものがなぜ混入したのか。。。。?
そもそも、「LSEP」とは??BOM的なモノ?
調べてみると、
こちらにあるように、どうも不可視文字なんだとか。
どうもエディタ固有の「行区切り」らしいです。
実際今回、本件の依頼者に入稿手順を確認してみたところ、
彼は、 mac標準の「メモ」を利用していました。
具体的には、
- パワポから「メモ」アプリへコピペ
- 「メモ」アプリ内で少し整形して、当社の社内管理サイトでプログラム入稿
をしていたとことで、目の前で作業をしてもらったところ再現しました
実態と原因が判明しました。
あとは、
- LSEPが混入しないようすること
- すでに混入してしまっているデータのクリーニング
をすればよさそうです。
1. LSEPが混入しないようする
所詮は文字コードなので、、、と調べてみると、こちらにphpでの実装例がありましたので、こちらをrubyで実装すれば、除去できそうです。
また、「文字列」の操作であることと、当社ではすでに、Ruby標準ライブラリであるStringを拡張したライブラリを使っていることからそこに組み込みば、より簡潔に対応できそうです。
...ということで、以下のように拡張してみました。
class String
:
def remove_lsep #
self.delete("\u2028")
end
end
あとはこれを使って、プログラム、イベントそれぞれの modelでbefore_validation処理として、
上記を用いて、デフォルトで除去する形にします。
class Clubs::Program < ApplicationRecord
include MediaPathUsable
include ImageResizable
include MediaStorable
mount_uploader :main_image_file_path, ::Clubs::ProgramUploader
:
before_validation do
self.content = content.remove_lsep if content
self.md_content = md_content.remove_lsep if md_content
self.participants_content = participants_content.remove_lsep if participants_content
self.md_participants_content = md_participants_content.remove_lsep if md_participants_content
end
:
end
すでに混入してしまっているデータのクリーニング
ここまでで、プログラム、イベントそれぞれのデータの追加、更新時に自動でLSEP除去が行われる状態になりました。
つまり、対象のデータをシンプルにそのままsaveすれば、更新がかかり、callback処理=before_savebefore_validation
に用意した処理が呼ばれるので、シンプルに以下のようにしてみました。
namespace :lesp_string do
desc 'remove'
task cleanup: :setup_logger do
Rake::Task['lesp_string:remove:programs'].execute
Rake::Task['lesp_string:remove:events'].execute
end
namespace :remove do
desc 'cleanup programs'
task programs: :setup_logger do
begin
ActiveRecord::Base.transaction do
updating_programs.each do |p|
p.save(validate: false)
p.preparations.each(&:save!)
end
end
rescue StandardError => e
puts e.message
end
end
desc 'cleanup events'
task events: :setup_logger do
begin
ActiveRecord::Base.transaction do
updating_events.each do |p|
p.save(validate: false)
p.preparations.each(&:save!)
end
end
rescue StandardError => e
puts e.message
end
end
end
def updating_programs
@programs ||= ::Clubs::Program.order(:created_at)
end
def updating_events
@events ||= ::Event.order(:created_at)
end
task setup_logger: :environment do
Rails.logger = Logger.new(STDOUT)
end
end
こちらをデプロイして、動作確認して、今回は無事、問題解消できました。
所感
最初はLSEPってなんだ?って驚きましたが、冷静に文字列処理で解決できることがわかれば、あとは、
Rails wayに則ったやりかたで、スリム対応ができるなと、実感した事案でした。
正直、Stringクラスを拡張していたこと自体忘れていましたが 今回はとても助かりました
今回のような例に限らず、弊社では、Railsを実直に利用し、できる限りRailに乗せた設計、コーディングを行なっています。結果的にそのほうが、新規開発、既存改修などあらゆる面で柔軟性があり、スピーディな実装が可能となるからです。OOPの実践についても、今後、ちょうどいい事案がありましたらまた、披露できたらと思います。
(要は、フレームワークやデザインパターンといった先人の知恵は積極的使うほうがbetter!という発想です w)
今回も恒例のやつですが
当社では、バックエンドサーバーとして主にRails、フロントエンドでは、Nextjsを利用しています。
新しい物(コト)好きの当社では、絶賛、エンジニアを募集中です!
気になる方はお気軽にご連絡いただけましたらと思います!
編集後記
コメントにあるとおり、@scivola さんからのご指摘を受け、一部、対応内容修正させていただきました。
ありがとうございます。’