Rendering Content & the Kanji Edge Case

Website Rebuild with Ruby on Rails

Chapter 7 · Rendering Content & the Kanji Edge Case

Kanji's two original constraints — a fixed-depth hierarchy with no natural slot for individual characters, and no self-contained-fragment convention for a page with inline stroke-animation markup — are already resolved the same way every sibling course resolved them: Chapter 2's arbitrary-depth Page model has no special-cased depth limit, and Chapter 4's <%== @page.body %> unescaped rendering lets a kanji page's own markup render through the exact same path as any other page. There's nothing new to solve there. What's worth checking carefully is whether Ruby introduces any new risk of its own.

Ruby's Strings: Closer to Python Than to PHP

title = "水のページ" title.length # => 5 — five characters, not the byte count title[0, 3] # => "水のペ" — sliced by character position

Ruby's String class carries its own encoding metadata (UTF-8 by default since Ruby 2.0), and every core method — length, [], slice, each_char — operates on characters in that encoding, never on raw bytes. There's no substr()-vs-mb_substr()-style split in Ruby at all, because there's no byte-oriented string family to accidentally reach for in the first place.

Not a new problem solved — a problem that was never introduced
This puts Ruby in the same category as Python 3, not PHP. Django's own Chapter 7 never needed to discuss string-slicing safety at all, because Python 3's str type is already Unicode-code-point-aware by design — the exact same reason Ruby doesn't need one here either. Laravel's Chapter 7 genuinely needed mb_substr(), because PHP's own core string functions operate on raw bytes by default. Rails doesn't inherit that risk, the same way Django didn't.

The Real Rails-Specific Detail: utf8mb4 by Default

# config/database.yml — generated automatically by # `rails new --database=mysql` since Rails 5.2 default: &default adapter: mysql2 encoding: utf8mb4 ...

MySQL's own legacy utf8 charset alias only supports up to 3 bytes per character — enough for most common kanji, but not for every 4-byte Unicode character (rarer CJK extension ideographs, most emoji). Rails has defaulted its own generated config/database.yml to the genuinely complete utf8mb4 encoding automatically since Rails 5.2, specifically because of this exact class of problem. Chapter 1's own rails new --database=mysql already produced a configuration with no manual fix needed here — a small, honest, positive finding, not a dramatic one, but a real one.

String Safety, Compared Across Four Languages

JavaScriptPython (Django)PHP (Laravel)Ruby (Rails)
Default string unitUTF-16 code unitsUnicode code pointsRaw bytesCharacters, per the string's own encoding
Slicing risk for common kanjiLow — most CJK ideographs are one UTF-16 unitNoneReal — substr() can split a multi-byte characterNone
Needed a safe alternative function?No, for typical CJK contentNoYes — mb_substr()No

Hands-On Exercises

Exercise 1

Explain why kanji's two original constraints from earlier in the series are already resolved for Rails without any new work in this chapter, and name the two specific earlier chapters responsible.

📄 View solution
Exercise 2

Explain why Ruby doesn't have a substr()-vs-mb_substr()-style split the way PHP does, and explain why this chapter compares Ruby to Python rather than treating it as a uniquely Rails-specific resolution.

📄 View solution
Exercise 3

Explain what MySQL's legacy utf8 charset alias actually fails to support, and explain why this course's own config/database.yml never needed a manual fix for it.

📄 View solution

Chapter 7 Quick Reference

  • Same resolution as every sibling — Chapter 2's arbitrary depth, Chapter 4's unescaped rendering
  • Ruby's String — encoding-aware by design; length/[]/slice operate on characters, never raw bytes
  • Closer to Python than PHP — no substr()-vs-mb_substr()-style split exists in Ruby, matching Django's own Python 3 strings
  • utf8mb4 by default — Rails' own generated database.yml has avoided MySQL's legacy 3-byte utf8 trap automatically since Rails 5.2
  • Next chapter: Dynamic Content & Forms