color_field のバリデーションを正確な 6 桁 HEX に限定

rails/rails

color_field が文字列中に 6 桁の HEX が含まれるだけで有効と判定し、ブラウザが解釈できない <input type="color"> を生成していた問題を、正確に "#rrggbb" 形式のみ受け付けるように修正しました。

背景

color_field の内部で使用されている validate_color_string が、以前は /#[0-9a-fA-F]{6}/ という正規表現で文字列中に 6 桁の十六進数が現れるかどうかだけをチェックしていました。その結果、"Not a color #123456 at all" のように HEX が部分文字列として含まれるだけの入力や、8 桁の #rrggbbaa 形式までが誤って有効と判断され、ブラウザが受け付けないカラーコードがそのまま出力されていました。PR の説明にある通り、実際に生成されたマークアップは <input type="color" value="#123456"> のようになり、ユーザー体験を損なうバグでした。

技術的な変更

正規表現のアンカー追加 によって、文字列全体が "#rrggbb" 形式に完全一致するかを検証するように変更しました。具体的な差分は次のとおりです。

@@ -13,7 +13,7 @@ def render

         private
           def validate_color_string(string)
-            regex = /#[0-9a-fA-F]{6}/
+            regex = /\A#[0-9a-fA-F]{6}\z/
             if regex.match?(string)
               string.downcase
             else

この変更により、文字列全体が "#rrggbb" の形でない限りマッチせず、#000000 にフォールバックされます。フォールバックロジックは既存コードと同一で、他の不正な入力(例: "#1234TR")と同様の挙動を保ちます。

テストも新たに追加され、"Not a color #123456 at all" のようなケースで期待通りに #000000 が出力されることが確認されています。

@@ -1147,6 +1147,12 @@ def test_color_field_with_invalid_hex_color_string
     assert_dom_equal(expected, color_field("car", "color"))
   end

+  def test_color_field_with_string_containing_hex_color_substring
+    expected = %{<input id="car_color" name="car[color]" type="color" value="#000000" />}
+    @car.color = "Not a color #123456 at all"
+    assert_dom_equal(expected, color_field("car", "color"))
+  end
+
   def test_color_field_with_value_attr
     expected = %{<input id="car_color" name="car[color]" type="color" value="#00FF00" />}
     assert_dom_equal(expected, color_field("car", "color", value: "#00FF00"))

設計判断

正規表現のアンカー化 というシンプルな修正で問題を解決した点が本 PR の設計上の選択です。新たにパラメータや設定項目を導入することなく、既存メソッドのロジックだけを変更し、後方互換性を維持しています。代替案としては入力文字列を正規表現以外でパースする、あるいは別のバリデーション層を追加するといった手段も考えられましたが、最小変更で確実に期待動作を得られる今回のアプローチが採択されました。

まとめ

color_field のバリデーションが文字列全体の "#rrggbb" 形式に限定されたことで、ブラウザが解釈できないカラーコードが生成されるケースが排除されました。この修正は正規表現のアンカー化だけで実装され、既存の API と互換性を保ちつつ、入力検証の堅牢性を向上させています。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
b5de3436

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文、背景、技術的変更、設計判断(任意)、まとめが全て揃っており、総論→各論→結論の構成が明確です。

カスタムMarkdown構文 ⚠ WARNING

シンタックスハイライト・GitHubリンク記法の正確性

ファイル名付きシンタックスハイライトは正しい形式ですが、PRリンクが "[PR #57989](URL)" となっており、要求された "[#57989](URL)" 形式になっていません。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

Rails エンジニア向けの専門的な内容で、過度な初心者向け説明はありません。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが総論・各論・結論の段落構成になっており、トピックセンテンスで始まり、1段落1トピックで適切な長さです。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

コードブロックは提供された Diff と完全に一致し、ファイル名・変更内容とも合致しています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

正規表現、アンカー、フォールバックなどの用語が正しく使用されており、PR の記述と一致しています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

技術的な説明は PR の内容と合致し、因果関係も論理的です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

全ての主張が PR の説明・Diff で裏付けられており、根拠のない推測や捏造はありません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR 番号 #57989 が正確に記載されており、他の数値や固有名詞に誤りはありません。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事タイトルは PR の修正内容を的確に要約しており、内容に矛盾はありません。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

外部のバージョンサポート情報やリリース日程等は記載されていません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

時間表現は使用されておらず、PR と食い違う表現もありません。