RubyやRailsのerbを用いて、文末を「...」に置き換える方法

# はじめに
オーバーフローしてしまったテキストの省略をさせる際に、文末を「…」などに置き換えたいことがあるかと思います。

```　
開発環境を紹介します。DBにはMySQLを使用しています。Mac OSのバージョンは...
```

CSSのtext-overflowでも適用できるみたいですが、今回はあえてRubyの力を頼りにしてみました。また、Railsのlink_toを使うことで「…」をリンク化する方法もご紹介します。

---

# Rubyの場合
Rubyでは表示したい文字列の操作や、文字列内に式や変数を組み込むことが簡単にできます。

```hoge.rb
exam_text = "テスト文章です。今日もいい天気ですね。懐が寒いです。"
```

以下の例では、変数exam_textに文字列を代入している前提で記述していきます。

## そのまま表示する

```hoge.rb
p exam_text
# => "テスト文章です。今日もいい天気ですね。懐が寒いです。"
```

## 表示する文字列の文字数を指定する。
**文字列[0, n]**と指定をすることで**先頭からn文字**を表示させることができます。

```hoge.rb
p exam_text[0, 10]
# => "テスト文章です。今日"
```

[10]と指定してしまうと、文字列の**0から数えて10番目**しか表示されないので要注意です。

```hoge.rb
p exam_text[10]
# => "も"
```

## 文字列の中で変数や式を展開する
"#{}"を使うことでその中に変数や式を記述できます。

```hoge.rb
p "ここから#{exam_text[0, 10]}…"
# => "ここからテスト文章です。今日…"
```

---

# Railsの場合
Railsの埋め込みRuby（erb）を使用すると、より豊かな表現ができるようになります。置き換えにはtruncateメソッドを、リンクの生成にはlink_toメソッドを使用することができます。

```***.html.erb
<% exam_text = "テスト文章です。今日もいい天気ですね。懐が寒いです。テスト文章です。今日もいい天気ですね。懐が寒いです。" %>
```
truncateメソッドを検証するため、変数exam_textには少し長めの例文を代入します。

## truncateメソッド

```
truncate(文字列[, オプション])
```

オプションでは以下の項目を指定できます。オプションを省略した場合、:lengthと:omissionのデフォルト値が適用されます。omissionのデフォルト値は3点リーダー（…）ではなく、ドット3つになります。

|オプション項目|説明|デフォルト値|
|:-----|:-----|:-----:|
|:length|切り捨ての桁数|30|
|:separator|切り捨てる箇所を表す文字列|なし|
|:omission|末尾に付与する文字列|...|



### 文字列だけ指定
```***.html.erb
<%= truncate(exam_text) %>
# => テスト文章です。今日もいい天気ですね。懐が寒いです。テ...
```
文字列だけ指定した場合、デフォルト値が存在する:lengthと:omissionが適用されます。文字列全体は30文字ですが、末尾から3文字がドット3つに置き換えられます。

### 末尾の文字を指定
今度は:omissionのデフォルト値を3点リーダーに置き換えてみます。

```***.html.erb
<%= truncate(exam_text, omission: "…") %>
# => テスト文章です。今日もいい天気ですね。懐が寒いです。テスト…
```

30文字以降は切り捨てられ、最後の一文字が置き換えられました。

```***.html.erb
<%= truncate(exam_text, omission: "続きを読む") %>
# => テスト文章です。今日もいい天気ですね。懐が寒いです続きを読む
```
置き換える文字が長くなるほど、表示したい文字列は短くなってしまいます。

### 切り捨ての桁数を指定
切り捨ての桁数を10、末尾の文字には三点リーダー指定してみます。

```***.html.erb
<%= truncate(exam_text, length: 10, omission: "…") %>
# => テスト文章です。今…
```

### 切り捨てる箇所を表す文字列を指定
:separatorを指定すると、その文字から後ろが切り捨てられるようになります。

```***.html.erb
<%= truncate(exam_text, length: 20, omission: "…") %>
# => テスト文章です。今日もいい天気ですね。…

<%= truncate(exam_text, length: 20, separator:"天", omission: "…") %>
# => テスト文章です。今日もいい…
```

同じ文字が複数存在する場合は、末尾に近い方が置き換えられます。

```***.html.erb
<%= truncate(exam_text, length: 20, separator:"。", omission: "…") %>
# => テスト文章です。今日もいい天気ですね…
```

## link_toメソッド
テキストに表示したい文字列、パスにはリンク先を指定することでリンクを生成することができます。頻出だと思いますので、詳細な説明は省略します。

```
link_to(テキスト, パス)
```

# …や文字列全体をリンクにする
ここまでの方法で、文字列を切り捨て・置き換えができるようになりました。次は…や文字列全体をリンクにすることに挑戦していきます。

「表示したい文字列全体は20文字、最後の文字は3点リーダーにして、3点リーダーをroot_pathへのリンクにする。」という条件です。

```
# => テスト文章です。今日もいい天気ですね。…
```
このように表示されたらOKとします。

## 文字数の指定とlink_toを使う
exam_textから19文字、最後の一文字は3点リーダーのリンクに置き換えることができました。

```***.html.erb
<%= exam_text[0, 19] %><%= link_to("…", root_path) %>
# => テスト文章です。今日もいい天気ですね。…
```

## truncateとlink_toを個別に使う
:omissionをあえて指定しないことで、link_toメソッドを組み合わせられるようになります。

```***.html.erb
<%= truncate(exam_text, length: 19, omission: "" ) %><%= link_to("…", root_path) %>
# => テスト文章です。今日もいい天気ですね。…
```

## truncateのomissionとlink_toを組み合わせると、うまくいかない
「omissionにlink_toを組み合わせてみたらうまくいくのでは!?」と思ったのですがダメでした。

```***.html.erb
<%= truncate(exam_text, length: 20, omission: link_to("…", root_path)) %>
# => テスト<a href="/">…</a>
```
うまくいきません。link_toメソッドで生成したリンクをエスケープさせているためだと思います。

エスケープをさせないようにするrawメソッドを組み合わせてみます。

```***.html.erb
<%= truncate(exam_text, length: 20, omission: raw(link_to("…", root_path))) %>
# => テスト<a href="/">…</a>
```
こちらもうまくいきませんでした。



#　最後に
もっとキレイな書き方が存在するかもしれません。もしご存じの方がみえたら教えていただけると幸いです。

(2021/12/11　追記)
@scivola様からtruncateメソッドと文字数の指定方法についてご教示いただきましたので、内容を更新しました。ありがとうございました。


（話が逸れますが、◯◯の方が**みえる**というのは東海三県の方言みたいですね。愛知県民ですので、なにも違和感がありませんでした。）

## 参考にしたページ

[Railsドキュメント 文字列を切り捨てる](https://railsdoc.com/page/truncate)
[Railsドキュメント エスケープしない](https://railsdoc.com/page/raw)
[Railsドキュメント リンクを生成](https://railsdoc.com/page/link_to)