<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>プログラミング - shungo blog</title>
	<atom:link href="https://shungoblog.com/programming/feed" rel="self" type="application/rss+xml" />
	<link>https://shungoblog.com</link>
	<description>しゅんごブログ</description>
	<lastBuildDate>Fri, 02 May 2025 11:23:49 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>

<image>
	<url>https://shungoblog.com/wp-content/uploads/2022/04/cropped-IMG_0718-32x32.jpg</url>
	<title>プログラミング - shungo blog</title>
	<link>https://shungoblog.com</link>
	<width>32</width>
	<height>32</height>
</image> 
<atom:link rel="hub" href="https://pubsubhubbub.appspot.com"/>
<atom:link rel="hub" href="https://pubsubhubbub.superfeedr.com"/>
<atom:link rel="hub" href="https://websubhub.com/hub"/>
<atom:link rel="self" href="https://shungoblog.com/programming/feed"/>
	<item>
		<title>【Git】Merge commitをrevertする方法 (error: commit xxx is a merge but no -m option was given.)</title>
		<link>https://shungoblog.com/programming/git-revert-merge-commit.html</link>
					<comments>https://shungoblog.com/programming/git-revert-merge-commit.html#respond</comments>
		
		<dc:creator><![CDATA[しゅんご]]></dc:creator>
		<pubDate>Mon, 29 May 2023 23:45:03 +0000</pubDate>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[git]]></category>
		<guid isPermaLink="false">https://shungoblog.com/?p=3084</guid>

					<description><![CDATA[<p>merge commitをrevertで取り消す時に、下記のエラーが出たことがないでしょうか？ % git revert 504c0d33 error: commit 504c0d33e29dc4488bd1b4eb95 [&#8230;]</p>
<p>The post <a href="https://shungoblog.com/programming/git-revert-merge-commit.html">【Git】Merge commitをrevertする方法 (error: commit xxx is a merge but no -m option was given.)</a> first appeared on <a href="https://shungoblog.com">shungo blog</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>merge commitをrevertで取り消す時に、下記のエラーが出たことがないでしょうか？</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>% git revert 504c0d33
error: commit 504c0d33e29dc4488bd1b4eb95574cd1f211fbcc is a merge but no -m option was given.
fatal: revert failed</code></pre>
</div>
<p>&nbsp;</p>
<div class="speech-wrap sb-id-11 sbs-flat sbp-l sbis-cb cf">
<div class="speech-person">
<figure class="speech-icon"><img fetchpriority="high" decoding="async" src="https://shungoblog.com/wp-content/uploads/2022/04/cropped-IMG_0718.jpg" alt="しゅんご" class="speech-icon-image" width="512" height="512" /></figure>
<div class="speech-name">しゅんご</div>
</div>
<div class="speech-balloon">
<p>この記事では、merge commitを取り消す方法をご紹介します！</p>
</div>
</div>
<p>&nbsp;</p>

  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-2" checked><label class="toc-title" for="toc-checkbox-2">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">そもそもRevertとは？</a><ol><li><a href="#toc2" tabindex="0">特定のcommitを打ち消すためのcommitを作成するコマンド</a></li><li><a href="#toc3" tabindex="0">オプション「-m」なしでmerge commitをrevertできない</a></li></ol></li><li><a href="#toc4" tabindex="0">Merge commitを取り消す方法 (オプション「-m」を指定する)</a><ol><li><a href="#toc5" tabindex="0">方法1. git revert -m 1 (基本的にこちらを使う)</a></li><li><a href="#toc6" tabindex="0">方法2. git revert -m 2</a></li></ol></li><li><a href="#toc7" tabindex="0">git revertの オプション「-m」について</a><ol><li><a href="#toc8" tabindex="0">「-m」はmainline(メインライン)を表す</a></li><li><a href="#toc9" tabindex="0">merge commitには2つの親commitがある</a></li></ol></li><li><a href="#toc10" tabindex="0">番外編: PRをGithubの画面から取り消す場合</a></li><li><a href="#toc11" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">そもそもRevertとは？</span></h2>
<h3><span id="toc2">特定のcommitを打ち消すためのcommitを作成するコマンド</span></h3>
<p>revertはcommitを打ち消すためのコマンドです。</p>
<p>revertすると、指定したcommitを取り消す、commitが作成されます。</p>
<p>&nbsp;</p>
<p>例えば下記のようなcommit(<code>47b4348</code>)があるとします。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>% git log --oneline
47b4348 commit-1</code></pre>
</div>
<p>このcommitを取り消したいときには、commitを指定してrevertします。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash">% git revert 47b4348</pre>
</div>
<p>すると、commit(<code>47b4348)</code>は取り消すための、新しいcommit(<code>566fa3e</code>)が追加されます。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>% git log --oneline
566fa3e Revert "commit-1"
47b4348 commit-1</code></pre>
</div>
<p>これが通常のcommitをrevertするときの流れです。</p>
<p>&nbsp;</p>
<h3><span id="toc3">オプション「-m」なしでmerge commitをrevertできない</span></h3>
<p>merge commitをrevertするときは、通常のcommitのrevertとは異なります。</p>
<p>&nbsp;</p>
<p>例えば、下記のようなPRのmerge commitを取り消す場合で考えてみます。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash">% git log --oneline
504c0d33 Merge pull request #123 from xxxxxx</pre>
</div>
<p>通常のcommitと同じようにmerge commitを指定してrevertしても、</p>
<p><span class="marker-under-red"><strong>「-m を指定していないのでrevertに失敗した」</strong></span>というエラーが出ます</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>% git revert 504c0d33
error: commit 504c0d33e29dc4488bd1b4eb95574cd1f211fbcc is a merge but no -m option was given.
fatal: revert failed</code></pre>
</div>
<div class="speech-wrap sb-id-11 sbs-flat sbp-l sbis-cb cf">
<div class="speech-person">
<figure class="speech-icon"><img fetchpriority="high" decoding="async" src="https://shungoblog.com/wp-content/uploads/2022/04/cropped-IMG_0718.jpg" alt="しゅんご" class="speech-icon-image" width="512" height="512" /></figure>
<div class="speech-name">しゅんご</div>
</div>
<div class="speech-balloon">
<p>merge commitをrevertする時には、</p>
<p><strong>オプション「-m 」</strong>を付けないと取り消すことができません。</p>
</div>
</div>
<p>&nbsp;</p>
<h2><span id="toc4">Merge commitを取り消す方法 (オプション「-m」を指定する)</span></h2>
<p>merge commitをrevertするには2つの方法があります。</p>
<p>例として、mainブランチにdevelopブランチをmergeしたcommitがあるとします。</p>
<p>&nbsp;</p>
<h3><span id="toc5">方法1. git revert -m 1 (基本的にこちらを使う)</span></h3>
<p>オプションで「-m 1」を指定すると、「mergeされたブランチ」の状態になります。</p>
<p><span class="marker-under-red"><strong>merge commitでrevertするときは、基本的にこちらを使用することがほとんどです。</strong></span></p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>% git revert -m 1 &lt;merge commit id&gt;</code></pre>
</div>
<p>例で説明すると、</p>
<p>mergeしたdevelopのcommitを削除して、developブランチをmerge前のmainブランチと同じ状態に戻ります。</p>
<p>&nbsp;</p>
<h3><span id="toc6">方法2. git revert -m 2</span></h3>
<p>オプションで「-m 2」を指定すると、「mergeしたブランチ」の状態になります。</p>
<p>こちらはほとんど使うことがないと思います。(私は使ったことがありません。。。)</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>% git revert -m 2 &lt;merge commit id&gt;</code></pre>
</div>
<p>例で説明すると、mainブランチがdevelopブランチと同じ状態になります。</p>
<p>&nbsp;</p>
<h2><span id="toc7">git revertの オプション「-m」について</span></h2>
<h3><span id="toc8">「-m」はmainline(メインライン)を表す</span></h3>
<p>revertコマンドのヘルプを見ると、</p>
<p><strong>「-m」はmainlineの省略であり、mainlineのparentを指定してください</strong>と書かれています。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>% git revert -h

<options><commit-ish>...<subcommand>
    --quit                end revert or cherry-pick sequence
    --continue            resume revert or cherry-pick sequence
    --abort               cancel revert or cherry-pick sequence
    --skip                skip current commit and continue
    --cleanup <mode>      how to strip spaces and #comments from message
    -n, --no-commit       don't automatically commit
    -e, --edit            edit the commit message
    -s, --signoff         add Signed-off-by:
    -m, --mainline <parent-number>
                          select mainline parent
    --rerere-autoupdate   update the index with reused conflict resolution if possible</parent-number></mode></subcommand></commit-ish></options></code></pre>
</div>
<p>参考: <a rel="nofollow noopener external" target="_blank" href="https://git-scm.com/docs/git-revert.html">revert | Git</a></p>
<p>&nbsp;</p>
<h3><span id="toc9">merge commitには2つの親commitがある</span></h3>
<p>merge commitの詳細を見てみると、</p>
<p>「<code>Merge: e41ec146 7f0af4ef</code>」とあり、commitが2つあることがわかります。</p>
<p>「mergeされたブランチのcommit」と「mergeしたブランチのcommit」です。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>% git show 504c0d33
commit 504c0d33e29dc4488bd1b4eb95574cd1f211fbcc (HEAD -&gt; main, origin/main)
Merge: e41ec146 7f0af4ef
Author: xxxxxxxxx
Date:   xxxxxxxxx</code></pre>
</div>
<p>左側のcommit(<code>e41ec146</code>)が「1」、右側のcommit(<code>7f0af4ef</code>)が「2」となっています。</p>
<p>&nbsp;</p>
<p>「-m」オプションでは「1」か「2」のどちらかを指定して、</p>
<p>どちらのブランチを正とするかを選択する必要があります。</p>
<p>&nbsp;</p>
<h2><span id="toc10">番外編: PRをGithubの画面から取り消す場合</span></h2>
<p>これまではコマンドでPRのmerge commitをrevertする方法を説明してきましたが、</p>
<p>Githubの画面からPRを取り消すことで、merge commitをrevertすることもできます。</p>
<p>参考までに添付しておきます！</p>
<p><a rel="nofollow noopener external" target="_blank" href="https://docs.github.com/ja/pull-requests/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/reverting-a-pull-request">Pull Request を打ち消す | Github</a></p>
<p>&nbsp;</p>
<h2><span id="toc11">まとめ</span></h2>
<p>下記のように、merge commitをrevertする方法は2つありますが、</p>
<p>「git revert -m 1」を使うことがほとんどだと思います。</p>
<p>&nbsp;</p>
<div class="scrollable-table"><table style="border-collapse: collapse; width: 100%; height: 123px;">
<tbody>
<tr style="height: 41px;">
<td style="width: 29.0598%; height: 41px;"><strong>コマンド</strong></td>
<td style="width: 37.6068%; height: 41px;"><strong>revert後</strong></td>
<td style="width: 33.3333%; height: 41px;"><strong>備考</strong></td>
</tr>
<tr style="height: 41px;">
<td style="width: 29.0598%; height: 41px;">git revert -m 1</td>
<td style="width: 37.6068%; height: 41px;">mergeされたブランチになる</td>
<td style="width: 33.3333%; height: 41px;">よく使用するのはこっち</td>
</tr>
<tr style="height: 41px;">
<td style="width: 29.0598%; height: 41px;">git revert -m 2</td>
<td style="width: 37.6068%; height: 41px;">mergeしたブランチになる</td>
<td style="width: 33.3333%; height: 41px;"></td>
</tr>
</tbody>
</table></div>
<p>&nbsp;</p>
<div class="speech-wrap sb-id-11 sbs-flat sbp-l sbis-cb cf">
<div class="speech-person">
<figure class="speech-icon"><img fetchpriority="high" decoding="async" src="https://shungoblog.com/wp-content/uploads/2022/04/cropped-IMG_0718.jpg" alt="しゅんご" class="speech-icon-image" width="512" height="512" /></figure>
<div class="speech-name">しゅんご</div>
</div>
<div class="speech-balloon">
<p>merge commitをrevertする方法がわからない方の</p>
<p>参考になれば幸いです！</p>
</div>
</div><p>The post <a href="https://shungoblog.com/programming/git-revert-merge-commit.html">【Git】Merge commitをrevertする方法 (error: commit xxx is a merge but no -m option was given.)</a> first appeared on <a href="https://shungoblog.com">shungo blog</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://shungoblog.com/programming/git-revert-merge-commit.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【Expo】eas build &#8211;platform iosでRun fastlaneがエラーになる</title>
		<link>https://shungoblog.com/programming/expo-eas-build-platform-ios-fastlane.html</link>
					<comments>https://shungoblog.com/programming/expo-eas-build-platform-ios-fastlane.html#respond</comments>
		
		<dc:creator><![CDATA[しゅんご]]></dc:creator>
		<pubDate>Fri, 28 Apr 2023 05:40:11 +0000</pubDate>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[expo]]></category>
		<category><![CDATA[react-native]]></category>
		<guid isPermaLink="false">https://shungoblog.com/?p=2480</guid>

					<description><![CDATA[<p>&#160; 目次 はじめにエラー内容エラーが発生したときの状況解決方法 (ライブラリのバージョンを更新)原因の特定方法まとめ はじめに React Nativeでアプリを開発している際、Expoを使用してeas bui [&#8230;]</p>
<p>The post <a href="https://shungoblog.com/programming/expo-eas-build-platform-ios-fastlane.html">【Expo】eas build –platform iosでRun fastlaneがエラーになる</a> first appeared on <a href="https://shungoblog.com">shungo blog</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>&nbsp;</p>

  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-4" checked><label class="toc-title" for="toc-checkbox-4">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">はじめに</a><ol><li><a href="#toc2" tabindex="0">エラー内容</a></li><li><a href="#toc3" tabindex="0">エラーが発生したときの状況</a></li></ol></li><li><a href="#toc4" tabindex="0">解決方法 (ライブラリのバージョンを更新)</a></li><li><a href="#toc5" tabindex="0">原因の特定方法</a></li><li><a href="#toc6" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p><span>React Nativeでアプリを開発している際、</span><span>Expoを使用して<code>eas build --platform ios</code>コマンドを実行したところ、</span></p>
<p><span>下記のように</span><span>Run fastlaneがエラーが出る場合がないでしょうか？</span></p>
<p>この記事ではその時の対処法をご紹介します！</p>
<p><img decoding="async" src="https://shungoblog.com/wp-content/uploads/2023/04/スクリーンショット-2023-04-28-11.26.38-300x152.png" alt="expo" width="589" height="298" class="wp-image-2484 aligncenter" srcset="https://shungoblog.com/wp-content/uploads/2023/04/スクリーンショット-2023-04-28-11.26.38-300x152.png 300w, https://shungoblog.com/wp-content/uploads/2023/04/スクリーンショット-2023-04-28-11.26.38-768x388.png 768w, https://shungoblog.com/wp-content/uploads/2023/04/スクリーンショット-2023-04-28-11.26.38.png 829w" sizes="(max-width: 589px) 100vw, 589px" /></p>
<h3><span id="toc2">エラー内容</span></h3>
<p><span><code>eas build --platform ios</code>を実行したときのエラー文です。</span></p>
<p>Run fastlaneの部分でエラーが発生しているようです。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-plain" data-lang="Plain Text"><code><span>Build failed: The "Run fastlane" step failed with an unknown error. Refer to "Xcode Logs" below for additional, more detailed logs.</span></code></pre>
</div>
<p>&nbsp;</p>
<h3><span id="toc3">エラーが発生したときの状況</span></h3>
<ul>
<li>Expoのバージョンを45 =&gt; 47にアップデートしたときにiosのbuildでエラーが発生した</li>
<li>androidの方はbuildできる</li>
<li>
<div>
<div><span>expo start でアプリは問題なく起動する</span></div>
<div></div>
</div>
</li>
</ul>
<h2><span id="toc4">解決方法 (ライブラリのバージョンを更新)</span></h2>
<div>私のプロジェクトの場合は、</div>
<div class="pr-1 flex-auto min-width-0"><code>@config-plugins/react-native-branch</code>のバージョンを2.0.0 =&gt; 最新の5.0.0にアップデートすることで解決しました！</div>
<div></div>
<div>下記は最新のバージョンに更新するときの実行コマンドです。</div>
<div>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-plain" data-lang="Plain Text">% expo install @config-plugins/react-native-branch</pre>
</div>
</div>
<p>&nbsp;</p>
<h2><span id="toc5">原因の特定方法</span></h2>
<p>ExpoにログインしてiOS App Store buildの画面を開きます。</p>
<p>下の方にRun fastlaneの項目があるのでクリックして詳細を開きます。</p>
<p><img decoding="async" src="https://shungoblog.com/wp-content/uploads/2023/04/スクリーンショット-2023-04-28-11.15.41-300x291.png" alt="expo" width="579" height="561" class="alignnone wp-image-2482" srcset="https://shungoblog.com/wp-content/uploads/2023/04/スクリーンショット-2023-04-28-11.15.41-300x291.png 300w, https://shungoblog.com/wp-content/uploads/2023/04/スクリーンショット-2023-04-28-11.15.41-768x744.png 768w, https://shungoblog.com/wp-content/uploads/2023/04/スクリーンショット-2023-04-28-11.15.41.png 853w" sizes="(max-width: 579px) 100vw, 579px" /></p>
<p>スクロールして中身を確認すると&#x274c;と表示されてエラーになっている部分があるので付近を確認すると<code>@config-plugins/react-native-branch</code>のライブラリあたりでエラーが出ていることが確認できます。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-plain" data-lang="Plain Text"><code>› Compiling @config-plugins/react-native-branch Pods/ExpoAdapterBranch » BranchAppDelegate.swift

&#x274c;  (node_modules/@config-plugins/react-native-branch/ios/ExpoAdapterBranch/BranchAppDelegate.swift:1:8)

&gt; 1 | import ExpoModulesCore
    |        ^ compiling for iOS 12.0, but module 'ExpoModulesCore' has a minimum deployment target of iOS 13.0: /Users/expo/Library/Developer/Xcode/DerivedData/IT-hfhagyzjhtdmvbfuwgocyplvlpbf/Build/Intermediates.noindex/ArchiveIntermediates/IT/BuildProductsPath/Release-iphoneos/ExpoModulesCore/ExpoModulesCore.swiftmodule/arm64-apple-ios.swiftmodule
  2 | import RNBranch
  3 | 
  4 | public class BranchAppDelegate: ExpoAppDelegateSubscriber {</code></pre>
</div>
<p>そのため、<code>@config-plugins/react-native-branch</code>のバージョンが適切でないと仮定して、ライブラリのバージョンを最新に更新したら、無事にbuildが成功しました！</p>
<p>&nbsp;</p>
<h2><span id="toc6">まとめ</span></h2>
<p>いろいろ記事を検索したり、issueを見たりしてみましたが、自分のプロジェクトに当てはまる解決方法が見つかりませんでした。</p>
<p>しかし、Expoの管理画面で実際のエラー内容をよく見てみると原因となっているライブラリを特定することができました。</p>
<p>&nbsp;</p><p>The post <a href="https://shungoblog.com/programming/expo-eas-build-platform-ios-fastlane.html">【Expo】eas build –platform iosでRun fastlaneがエラーになる</a> first appeared on <a href="https://shungoblog.com">shungo blog</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://shungoblog.com/programming/expo-eas-build-platform-ios-fastlane.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【Rails】文字列をBooleanに変換する方法 (ActiveRecord::Type::Boolean.new.cast)</title>
		<link>https://shungoblog.com/programming/rails-string-to-boolean-cast.html</link>
					<comments>https://shungoblog.com/programming/rails-string-to-boolean-cast.html#respond</comments>
		
		<dc:creator><![CDATA[しゅんご]]></dc:creator>
		<pubDate>Tue, 14 Mar 2023 00:29:45 +0000</pubDate>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[エンジニア]]></category>
		<guid isPermaLink="false">https://shungoblog.com/?p=2116</guid>

					<description><![CDATA[<p>目次 はじめにActiveRecord::Type::Boolean.new.castで変換するコードの定義についてよく使用する変換例メソッドで定義して使い回す方法クラスメソッドで定義するStringクラスのメソッドとし [&#8230;]</p>
<p>The post <a href="https://shungoblog.com/programming/rails-string-to-boolean-cast.html">【Rails】文字列をBooleanに変換する方法 (ActiveRecord::Type::Boolean.new.cast)</a> first appeared on <a href="https://shungoblog.com">shungo blog</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-6" checked><label class="toc-title" for="toc-checkbox-6">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">はじめに</a></li><li><a href="#toc2" tabindex="0">ActiveRecord::Type::Boolean.new.castで変換する</a></li><li><a href="#toc3" tabindex="0">コードの定義について</a></li><li><a href="#toc4" tabindex="0">よく使用する変換例</a></li><li><a href="#toc5" tabindex="0">メソッドで定義して使い回す方法</a><ol><li><a href="#toc6" tabindex="0">クラスメソッドで定義する</a></li><li><a href="#toc7" tabindex="0">Stringクラスのメソッドとして定義する</a></li></ol></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p>Rubyではboolean判定するには少し工夫が必要です。</p>
<p>自作でメソッドを定義することも可能ですが、<strong>ActiveRecord</strong>に便利なメソッドがあるので、</p>
<p>それを用いてBooleanに変換する方法をご紹介します。</p>
<p>&nbsp;</p>
<h2><span id="toc2"><span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Type</span><span class="o">::</span><span class="no">Boolean</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">castで変換する</span></span></h2>
<p>下記のようにActiveRecordのメソッドを使用することで</p>
<p>文字列をBooleanに変換することができます。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-ruby" data-lang="Ruby"><code>ActiveRecord::Type::Boolean.new.cast('true') # =&gt; true
ActiveRecord::Type::Boolean.new.cast('false') # =&gt; false
</code></pre>
</div>
<p>&nbsp;</p>
<h2><span id="toc3">コードの定義について</span></h2>
<p>変換するメソッドは下記で定義されています。</p>
<p><a rel="nofollow noopener external" target="_blank" href="https://github.com/rails/rails/blob/61fb58f6a7f852d765d616d1da41d17851ec7afc/activemodel/lib/active_model/type/boolean.rb"><span>rails/activemodel/lib/active_model/type/boolean.rb</span></a></p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-ruby" data-lang="Ruby"><code>module ActiveModel
  module Type

    ...
    class Boolean &lt; Value
      FALSE_VALUES = [
        false, 0,
        "0", :"0",
        "f", :f,
        "F", :F,
        "false", :false,
        "FALSE", :FALSE,
        "off", :off,
        "OFF", :OFF,
      ].to_set.freeze

      ...
      private
        def cast_value(value)
          if value == ""
            nil
          else
            !FALSE_VALUES.include?(value)
          end
        end
    end
  end
end</code></pre>
</div>
<p>大まかな処理の流れは下記の通りです。</p>
<ol>
<li>valueが空文字&#8221;&#8221; =&gt; nil</li>
<li>valueが<code>FALSE_VALUES</code>に含まれる値 =&gt; false</li>
<li>上記でない =&gt; true<code></code></li>
</ol>
<p>&nbsp;</p>
<h2><span id="toc4">よく使用する変換例</span></h2>
<p><strong>&#8216;true&#8217;</strong>や<strong>&#8216;false&#8217;</strong>以外にもよく使用するであろう値の変換結果を載せておきます。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-ruby" data-lang="Ruby"><code>ActiveRecord::Type::Boolean.new.cast('0') # =&gt; false
ActiveRecord::Type::Boolean.new.cast(0) # =&gt; false
ActiveRecord::Type::Boolean.new.cast('false') # =&gt; false
ActiveRecord::Type::Boolean.new.cast("FALSE") # =&gt; false
ActiveRecord::Type::Boolean.new.cast("off") # =&gt; false
ActiveRecord::Type::Boolean.new.cast("OFF") # =&gt; false

ActiveRecord::Type::Boolean.new.cast('1') # =&gt; true
ActiveRecord::Type::Boolean.new.cast(1) # =&gt; true
ActiveRecord::Type::Boolean.new.cast('true') # =&gt; true
ActiveRecord::Type::Boolean.new.cast('TRUE') # =&gt; true
ActiveRecord::Type::Boolean.new.cast('on') # =&gt; true
ActiveRecord::Type::Boolean.new.cast('ON') # =&gt; true

ActiveRecord::Type::Boolean.new.cast('') # =&gt; nil
ActiveRecord::Type::Boolean.new.cast(nil) # =&gt; nil
</code></pre>
</div>
<p>&nbsp;</p>
<h2><span id="toc5">メソッドで定義して使い回す方法</span></h2>
<p>下記のようにクラスメソッドで定義すれば、かなり使いやすくなるのでオススメです！！</p>
<h3><span id="toc6">クラスメソッドで定義する</span></h3>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-ruby" data-lang="Ruby"><code>class Utility
  def self.to_bool(value)
    ActiveRecord::Type::Boolean.new.cast(value)
  end
end

&gt; Utility.to_bool('true')
true</code></pre>
</div>
<h3><span id="toc7">Stringクラスのメソッドとして定義する</span></h3>
<p>下記にようにStringクラスで定義すれば、文字列全体に適用可能です。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-ruby" data-lang="Ruby"><code>class String
  def to_bool
    ActiveRecord::Type::Boolean.new.cast(self)
  end
end

&gt; 'true'.to_bool
true</code></pre>
</div><p>The post <a href="https://shungoblog.com/programming/rails-string-to-boolean-cast.html">【Rails】文字列をBooleanに変換する方法 (ActiveRecord::Type::Boolean.new.cast)</a> first appeared on <a href="https://shungoblog.com">shungo blog</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://shungoblog.com/programming/rails-string-to-boolean-cast.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【Ruby】 クラスメソッドからプライベートメソッドを呼ぶ方法</title>
		<link>https://shungoblog.com/programming/ruby-class-and-private-method.html</link>
					<comments>https://shungoblog.com/programming/ruby-class-and-private-method.html#respond</comments>
		
		<dc:creator><![CDATA[しゅんご]]></dc:creator>
		<pubDate>Sun, 12 Mar 2023 12:59:01 +0000</pubDate>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[エンジニア]]></category>
		<guid isPermaLink="false">https://shungoblog.com/?p=2105</guid>

					<description><![CDATA[<p>目次 はじめにNGなパターン1. クラスメソッドからプライベートメソッドを呼ぶ2. private内でself.methodを定義するクラスメソッドからプライベートメソッドを呼ぶ書き方 はじめに Rubyでクラスメソッド [&#8230;]</p>
<p>The post <a href="https://shungoblog.com/programming/ruby-class-and-private-method.html">【Ruby】 クラスメソッドからプライベートメソッドを呼ぶ方法</a> first appeared on <a href="https://shungoblog.com">shungo blog</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-8" checked><label class="toc-title" for="toc-checkbox-8">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">はじめに</a></li><li><a href="#toc2" tabindex="0">NGなパターン</a><ol><li><a href="#toc3" tabindex="0">1. クラスメソッドからプライベートメソッドを呼ぶ</a></li><li><a href="#toc4" tabindex="0">2. private内でself.methodを定義する</a></li></ol></li><li><a href="#toc5" tabindex="0">クラスメソッドからプライベートメソッドを呼ぶ書き方</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p>Rubyでクラスメソッド内からprivateメソッドを呼び出したときに、</p>
<p>エラーが発生したのでそのときの対処法をご紹介します。</p>
<p>&nbsp;</p>
<h2><span id="toc2">NGなパターン</span></h2>
<h3><span id="toc3">1. クラスメソッドからプライベートメソッドを呼ぶ</span></h3>
<p>私が最初に書いたエラーになるパターンのコードです。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-ruby" data-lang="Ruby"><code>class Sample1
  def self.foo
    bar
  end

  private

    def bar
      puts 'bar'
    end
end

&gt; Sample1.foo
Traceback (most recent call last):
1: from test.rb:13:in `&lt;main&gt;'
test.rb:3:in `foo': undefined local variable or method `bar' for Sample1:Class (NameError)</code></pre>
</div>
<p>&nbsp;</p>
<h3><span id="toc4">2. private内でself.methodを定義する</span></h3>
<p>こちらの場合は、エラーなく実行できますが、</p>
<p>privateメソッドを直接呼び出せてしまっているのでNGですね。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-ruby" data-lang="Ruby"><code>class Sample1
  def self.foo
    bar
  end

  private

    def self.bar
      puts 'bar'
    end
end

// エラーなく実行できる
&gt; Sample1.foo
bar

// privateメソッドを呼べている
&gt; Sample1.bar
bar</code></pre>
</div>
<p>&nbsp;</p>
<h2><span id="toc5">クラスメソッドからプライベートメソッドを呼ぶ書き方</span></h2>
<p>特異クラス内でprivateを定義すれば、</p>
<p>クラスメソッドからプライベートメソッドを呼ぶことが可能になります。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-ruby" data-lang="Ruby"><code>class Sample2
  class &lt;&lt; self # クラスメソッドで定義
    def foo
      bar
    end

    private

      def bar # クラスメソッド内でprivateメソッドを定義する
        puts 'bar'
      end
  end
end

&gt; Sample2.foo
bar</code></pre>
</div>
<p>最初のように<code>def sefl.method end</code>の書き方に合わせるなら</p>
<p>下記のようになります。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-ruby" data-lang="Ruby"><code>class Sample2
  def self.foo # クラスメソッドで定義
    bar
  end
  class &lt;&lt; self

    private

      def bar # 特異クラス内でprivateメソッドを定義する
        puts 'bar'
      end
  end
end

&gt; Sample2.foo
bar</code></pre>
</div><p>The post <a href="https://shungoblog.com/programming/ruby-class-and-private-method.html">【Ruby】 クラスメソッドからプライベートメソッドを呼ぶ方法</a> first appeared on <a href="https://shungoblog.com">shungo blog</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://shungoblog.com/programming/ruby-class-and-private-method.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SequelProでER図を出力する方法</title>
		<link>https://shungoblog.com/programming/sequel-erd.html</link>
					<comments>https://shungoblog.com/programming/sequel-erd.html#respond</comments>
		
		<dc:creator><![CDATA[しゅんご]]></dc:creator>
		<pubDate>Sat, 25 Feb 2023 00:57:37 +0000</pubDate>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[ER図]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[sequel]]></category>
		<guid isPermaLink="false">https://shungoblog.com/?p=2001</guid>

					<description><![CDATA[<p>目次 はじめに出力するテーブルSequelProでDotをエクスポートするGraphvizをインストールターミナルでDotをPngに変換する はじめに SequelProで接続したDBをER図に出力する方法をご紹介します [&#8230;]</p>
<p>The post <a href="https://shungoblog.com/programming/sequel-erd.html">SequelProでER図を出力する方法</a> first appeared on <a href="https://shungoblog.com">shungo blog</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-10" checked><label class="toc-title" for="toc-checkbox-10">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">はじめに</a></li><li><a href="#toc2" tabindex="0">出力するテーブル</a></li><li><a href="#toc3" tabindex="0">SequelProでDotをエクスポートする</a></li><li><a href="#toc4" tabindex="0">Graphvizをインストール</a></li><li><a href="#toc5" tabindex="0">ターミナルでDotをPngに変換する</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p>SequelProで接続したDBをER図に出力する方法をご紹介します。</p>
<p>Dockerで起動したDBにSequelProで接続する方法は下記の記事をご覧下さい。</p>
<p><img loading="lazy" decoding="async" src="https://shungoblog.com/wp-content/uploads/2023/02/development-300x234.png" alt="er" width="300" height="234" class="size-medium wp-image-2021 aligncenter" srcset="https://shungoblog.com/wp-content/uploads/2023/02/development-300x234.png 300w, https://shungoblog.com/wp-content/uploads/2023/02/development.png 423w" sizes="(max-width: 300px) 100vw, 300px" /></p>
<p>&nbsp;</p>

<a target="_blank" href="https://shungoblog.com/docker-mysql-sequel-pro/" title="DockerのMySQLコンテナにSequel proで接続する方法" class="blogcard-wrap external-blogcard-wrap a-wrap cf"><div class="blogcard external-blogcard eb-left cf"><div class="blogcard-label external-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail external-blogcard-thumbnail"><img loading="lazy" decoding="async" src="https://shungoblog.com/wp-content/uploads/cocoon-resources/blog-card-cache/5411650c615ce76a29cab44447468719.png" alt="" class="blogcard-thumb-image external-blogcard-thumb-image" width="320" height="180" /></figure><div class="blogcard-content external-blogcard-content"><div class="blogcard-title external-blogcard-title">DockerのMySQLコンテナにSequel proで接続する方法</div><div class="blogcard-snippet external-blogcard-snippet">docker composeで起動したのMySQLコンテナにSequel proで接続する方法をご紹介します。またSequelを使用せず、コマンドでMySQLコンテナに接続する方法もご説明します。</div></div><div class="blogcard-footer external-blogcard-footer cf"><div class="blogcard-site external-blogcard-site"><div class="blogcard-favicon external-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://shungoblog.com/programming/docker-mysql-sequel-pro.html" alt="" class="blogcard-favicon-image external-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain external-blogcard-domain">shungoblog.com</div></div></div></div></a>
<h2><span id="toc2">出力するテーブル</span></h2>
<p>今回出力するのはparentテーブルとchildrenテーブルです。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-sql" data-lang="SQL"><code>create table parent (
  id bigint not null auto_increment,
  name varchar(255),
  primary key (id)
);

create table children (
  id bigint not null auto_increment,
  parent_id bigint not null,
  name varchar(255),
  primary key (id),
  foreign key (parent_id) references parent (id) on delete restrict
);</code></pre>
</div>
<p>&nbsp;</p>
<h2><span id="toc3">SequelProでDotをエクスポートする</span></h2>
<p>Sequelのファイル &gt; エクスポートを押します。</p>
<p><img loading="lazy" decoding="async" src="https://shungoblog.com/wp-content/uploads/2023/02/スクリーンショット-2023-02-25-9.28.10-300x172.jpg" alt="sequel-1" width="553" height="317" class="wp-image-2019 aligncenter" srcset="https://shungoblog.com/wp-content/uploads/2023/02/スクリーンショット-2023-02-25-9.28.10-300x172.jpg 300w, https://shungoblog.com/wp-content/uploads/2023/02/スクリーンショット-2023-02-25-9.28.10-1024x587.jpg 1024w, https://shungoblog.com/wp-content/uploads/2023/02/スクリーンショット-2023-02-25-9.28.10-768x440.jpg 768w, https://shungoblog.com/wp-content/uploads/2023/02/スクリーンショット-2023-02-25-9.28.10-120x68.jpg 120w, https://shungoblog.com/wp-content/uploads/2023/02/スクリーンショット-2023-02-25-9.28.10.jpg 1470w" sizes="(max-width: 553px) 100vw, 553px" /></p>
<p>エクスポートする形式を選択するモーダルが出ます。</p>
<p>Dotを選択してエクスポートします。今回はDesktopに出力しています。</p>
<p><img loading="lazy" decoding="async" src="https://shungoblog.com/wp-content/uploads/2023/02/スクリーンショット-2023-02-25-9.28.26-300x290.jpg" alt="sequel-2" width="476" height="460" class="wp-image-2020 aligncenter" srcset="https://shungoblog.com/wp-content/uploads/2023/02/スクリーンショット-2023-02-25-9.28.26-300x290.jpg 300w, https://shungoblog.com/wp-content/uploads/2023/02/スクリーンショット-2023-02-25-9.28.26-1024x989.jpg 1024w, https://shungoblog.com/wp-content/uploads/2023/02/スクリーンショット-2023-02-25-9.28.26-768x742.jpg 768w, https://shungoblog.com/wp-content/uploads/2023/02/スクリーンショット-2023-02-25-9.28.26.jpg 1054w" sizes="(max-width: 476px) 100vw, 476px" /></p>
<h2><span id="toc4">Graphvizをインストール</span></h2>
<p><span><a rel="nofollow noopener external" target="_blank" href="https://graphviz.org/">Graphviz</a>はdot言語で記述されたグラフ構造を画像ファイルへ出力するツールです。</span></p>
<p>Sequelで出力してDot形式をPngに変換するために使用します。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>% <span>brew install graphviz</span></code></pre>
</div>
<h2><span id="toc5">ターミナルでDotをPngに変換する</span></h2>
<p>Sequelで出力した<code>development.dot</code>を<code>development.png</code>に変換します。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>% dot -Tpng development.dot &gt; development.png</code></pre>
</div>
<p>そうすると、このようにER図を画像で表示することができます！</p>
<p><img loading="lazy" decoding="async" src="https://shungoblog.com/wp-content/uploads/2023/02/development-300x234.png" alt="er" width="368" height="287" class="wp-image-2021 aligncenter" srcset="https://shungoblog.com/wp-content/uploads/2023/02/development-300x234.png 300w, https://shungoblog.com/wp-content/uploads/2023/02/development.png 423w" sizes="(max-width: 368px) 100vw, 368px" /></p><p>The post <a href="https://shungoblog.com/programming/sequel-erd.html">SequelProでER図を出力する方法</a> first appeared on <a href="https://shungoblog.com">shungo blog</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://shungoblog.com/programming/sequel-erd.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【MySQL】 外部キー制約 (restrict / cascade / set null)</title>
		<link>https://shungoblog.com/programming/mysql-foreign-key-constraint.html</link>
					<comments>https://shungoblog.com/programming/mysql-foreign-key-constraint.html#respond</comments>
		
		<dc:creator><![CDATA[しゅんご]]></dc:creator>
		<pubDate>Fri, 24 Feb 2023 12:15:31 +0000</pubDate>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[rails]]></category>
		<guid isPermaLink="false">https://shungoblog.com/?p=1987</guid>

					<description><![CDATA[<p>Railsの場合、modelでdependent: :destroyなどで指定できる外部キー制約を MySQLの場合どのようにすれば指定できるかをまとめてみました。 目次 外部キー制約の種類動作確認restrictcas [&#8230;]</p>
<p>The post <a href="https://shungoblog.com/programming/mysql-foreign-key-constraint.html">【MySQL】 外部キー制約 (restrict / cascade / set null)</a> first appeared on <a href="https://shungoblog.com">shungo blog</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Railsの場合、modelで<code>dependent: :destroy</code>などで指定できる外部キー制約を</p>
<p>MySQLの場合どのようにすれば指定できるかをまとめてみました。</p>

  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-12" checked><label class="toc-title" for="toc-checkbox-12">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">外部キー制約の種類</a></li><li><a href="#toc2" tabindex="0">動作確認</a><ol><li><a href="#toc3" tabindex="0">restrict</a></li><li><a href="#toc4" tabindex="0">cascade</a></li><li><a href="#toc5" tabindex="0">set null</a></li></ol></li><li><a href="#toc6" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">外部キー制約の種類</span></h2>
<p>まずは外部キー制約の種類です。</p>
<div class="scrollable-table"><table style="border-collapse: collapse; width: 100%;">
<tbody>
<tr style="background: #cdcdcd;">
<td style="width: 30.464%;"><strong>外部キー制約</strong></td>
<td style="width: 69.536%;"><strong>親のデータを削除した時の挙動</strong></td>
</tr>
<tr>
<td style="width: 30.464%;">restrict</td>
<td style="width: 69.536%;">エラーになる(削除できない)</td>
</tr>
<tr>
<td style="width: 30.464%;">cascade</td>
<td style="width: 69.536%;">子のデータも消える</td>
</tr>
<tr>
<td style="width: 30.464%;">set null</td>
<td style="width: 69.536%;">childrenのparent_idがnullになる</td>
</tr>
</tbody>
</table></div>
<p>&nbsp;</p>
<h2><span id="toc2">動作確認</span></h2>
<p>テーブル作成、データ挿入して、親データを削除したときにどのような挙動になるかを確認してみます。</p>
<p>parentテーブルとchildrenテーブルを作成して、</p>
<p>parentデータ1件、それに紐づくchildrenデータを2件挿入します。</p>
<h3><span id="toc3">restrict</span></h3>
<p>テーブルを作成します。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-sql" data-lang="SQL"><code>create table parent (
  id bigint not null auto_increment,
  name varchar(255),
  primary key (id)
);

create table children (
  id bigint not null auto_increment,
  parent_id bigint not null,  -- NOTE: not null制約
  name varchar(255),
  primary key (id),
  foreign key (parent_id) references parent (id) on delete restrict -- NOTE: restrict制約
);</code></pre>
</div>
<p>次にデータ挿入します。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-sql" data-lang="SQL"><code>insert into parent (name) values ('name');

-- NOTE: parentに紐づくchidrenデータ
insert into children (name, parent_id) values ('children1', 1); 
insert into children (name, parent_id) values ('children2', 1);</code></pre>
</div>
<p>挿入したデータを確認します。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-sql" data-lang="SQL"><code>mysql&gt; select * from parent;
+----+------+
| id | name |
+----+------+
|  1 | name |
+----+------+

mysql&gt; select * from children;
+----+-----------+-----------+
| id | parent_id | name      |
+----+-----------+-----------+
|  1 |         1 | children1 |
|  2 |         1 | children2 |
+----+-----------+-----------+</code></pre>
</div>
<p>この状態でparentデータを削除してみます。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-sql" data-lang="SQL"><code>mysql&gt; delete from parent where id = 1;
ERROR 1451 (23000): Cannot delete or update a parent row: 
a foreign key constraint fails (`development`.`children`, CONSTRAINT `children_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`))
</code></pre>
</div>
<p><span class="marker-under-red">restrictの場合は、このように外部キーのエラーが出てデータを削除することができません。</span></p>
<p>&nbsp;</p>
<h3><span id="toc4">cascade</span></h3>
<p>続いてcascadeです。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-sql" data-lang="SQL"><code>-- NOTE: 必要に応じてテーブルを削除してください。
drop table children;
drop table parent;

-- NOTE: テーブル作成
create table parent (
  id bigint not null auto_increment,
  name varchar(255),
  primary key (id)
);

create table children (
  id bigint not null auto_increment,
  parent_id bigint not null,　-- NOTE: not null制約
  name varchar(255),
  primary key (id),
  foreign key (parent_id) references parent (id) on delete cascade　-- NOTE: cascade制約
);</code></pre>
</div>
<p>こちらも同じくデータを挿入します。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-sql" data-lang="SQL"><code>insert into parent (name) values ('name');

-- NOTE: parentに紐づくchidrenデータ
insert into children (name, parent_id) values ('children1', 1); 
insert into children (name, parent_id) values ('children2', 1);</code></pre>
</div>
<p>この状態でparentデータを削除してみます。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-sql" data-lang="SQL"><code>mysql&gt; delete from parent where id = 1;
Query OK, 1 row affected (0.02 sec)</code></pre>
</div>
<p>今度はデータを削除することができました。</p>
<p>selectでそれぞれのデータを確認してみます。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-sql" data-lang="SQL"><code>mysql&gt; select * from parent;
Empty set (0.00 sec)

mysql&gt; select * from children;
Empty set (0.01 sec)</code></pre>
</div>
<p><span class="marker-under-red">cascadeの場合、親データを削除するとそれに紐づく子のデータも削除されていることが確認できます。</span></p>
<p>&nbsp;</p>
<h3><span id="toc5">set null</span></h3>
<p>最後にset nullです。</p>
<p>restrictとcascadeと異なり、parent_idにnullを許容することに注意しましょう。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-sql" data-lang="SQL"><code>-- NOTE: 必要に応じてテーブルを削除してください。
drop table children;
drop table parent;

-- NOTE: テーブル作成
create table parent (
  id bigint not null auto_increment,
  name varchar(255),
  primary key (id)
);

create table children (
  id bigint not null auto_increment,
  parent_id bigint, -- NOTE: null許容
  name varchar(255),
  primary key (id),
  foreign key (parent_id) references parent (id) on delete set null -- NOTE: set null制約
);</code></pre>
</div>
<p>データを挿入します。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-sql" data-lang="SQL"><code>insert into parent (name) values ('name');

-- NOTE: parentに紐づくchidrenデータ
insert into children (name, parent_id) values ('children1', 1); 
insert into children (name, parent_id) values ('children2', 1);</code></pre>
</div>
<p><span>この状態でparentデータを削除してみます。</span></p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-sql" data-lang="SQL"><code>mysql&gt; delete from parent where id = 1;
Query OK, 1 row affected (0.02 sec)</code></pre>
</div>
<p>データを削除することができたのでデータを確認してみます。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-sql" data-lang="SQL"><code>mysql&gt; select * from parent;
Empty set (0.01 sec)

mysql&gt; select * from children;
+----+-----------+-----------+
| id | parent_id | name      |
+----+-----------+-----------+
|  1 |      NULL | children1 |
|  2 |      NULL | children2 |
+----+-----------+-----------+
2 rows in set (0.00 sec)</code></pre>
</div>
<p><span class="marker-under-red">親のデータは削除されており、子のデータは残っています。</span></p>
<p><span class="marker-under-red">set nullを指定しているので、parent_idはnullになっていることが確認できます。</span></p>
<p>&nbsp;</p>
<h2><span id="toc6">まとめ</span></h2>
<p>外部キー制約のrestrict, cascade, set nullの設定方法と挙動について確認しました。</p>
<p>必要に応じて外部キー制約を付与して、データの安全性を担保しましょう！</p>
<p>&nbsp;</p>
<div class="blogcard-type bct-together">

<a target="_blank" href="https://shungoblog.com/docker-mysql-sequel-pro/" title="DockerのMySQLコンテナにSequel proで接続する方法" class="blogcard-wrap external-blogcard-wrap a-wrap cf"><div class="blogcard external-blogcard eb-left cf"><div class="blogcard-label external-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail external-blogcard-thumbnail"><img loading="lazy" decoding="async" src="https://shungoblog.com/wp-content/uploads/cocoon-resources/blog-card-cache/5411650c615ce76a29cab44447468719.png" alt="" class="blogcard-thumb-image external-blogcard-thumb-image" width="320" height="180" /></figure><div class="blogcard-content external-blogcard-content"><div class="blogcard-title external-blogcard-title">DockerのMySQLコンテナにSequel proで接続する方法</div><div class="blogcard-snippet external-blogcard-snippet">docker composeで起動したのMySQLコンテナにSequel proで接続する方法をご紹介します。またSequelを使用せず、コマンドでMySQLコンテナに接続する方法もご説明します。</div></div><div class="blogcard-footer external-blogcard-footer cf"><div class="blogcard-site external-blogcard-site"><div class="blogcard-favicon external-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://shungoblog.com/programming/docker-mysql-sequel-pro.html" alt="" class="blogcard-favicon-image external-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain external-blogcard-domain">shungoblog.com</div></div></div></div></a>
</div><p>The post <a href="https://shungoblog.com/programming/mysql-foreign-key-constraint.html">【MySQL】 外部キー制約 (restrict / cascade / set null)</a> first appeared on <a href="https://shungoblog.com">shungo blog</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://shungoblog.com/programming/mysql-foreign-key-constraint.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【Go】 import cycle not allowed (循環参照)について</title>
		<link>https://shungoblog.com/programming/go-import-cycle-not-allowed.html</link>
					<comments>https://shungoblog.com/programming/go-import-cycle-not-allowed.html#respond</comments>
		
		<dc:creator><![CDATA[しゅんご]]></dc:creator>
		<pubDate>Thu, 23 Feb 2023 13:57:43 +0000</pubDate>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[go]]></category>
		<category><![CDATA[エンジニア]]></category>
		<guid isPermaLink="false">https://shungoblog.com/?p=1985</guid>

					<description><![CDATA[<p>目次 import cycle not allowed (循環参照とは？)循環参照が起こるコード例ファイル構成go.modmain.goa.gob.gomain.goを実行してみる循環参照の対策方法 import cyc [&#8230;]</p>
<p>The post <a href="https://shungoblog.com/programming/go-import-cycle-not-allowed.html">【Go】 import cycle not allowed (循環参照)について</a> first appeared on <a href="https://shungoblog.com">shungo blog</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-14" checked><label class="toc-title" for="toc-checkbox-14">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">import cycle not allowed (循環参照とは？)</a></li><li><a href="#toc2" tabindex="0">循環参照が起こるコード例</a><ol><li><a href="#toc3" tabindex="0">ファイル構成</a></li><li><a href="#toc4" tabindex="0">go.mod</a></li><li><a href="#toc5" tabindex="0">main.go</a></li><li><a href="#toc6" tabindex="0">a.go</a></li><li><a href="#toc7" tabindex="0">b.go</a></li></ol></li><li><a href="#toc8" tabindex="0">main.goを実行してみる</a></li><li><a href="#toc9" tabindex="0">循環参照の対策方法</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">import cycle not allowed (循環参照とは？)</span></h2>
<p><span>他のpackageにimportしたときに、こんなエラーが出た人はいるんではないでしょうか？</span></p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>import cycle not allowed</code></pre>
</div>
<p>このエラーは循環参照が起きているときの吐かれるエラーです。</p>
<p>&nbsp;</p>
<p>たとえばpackage aとbがあった場合に、</p>
<ul>
<li><strong>package aでbの関数やメソッドを参照している</strong></li>
<li><strong>package bでもaの関数やメソッドを参照している</strong></li>
</ul>
<p>と循環参照していることになり、<code>import cycle not allowed</code>というエラーが出てしまいます。</p>
<p>&nbsp;</p>
<h2><span id="toc2">循環参照が起こるコード例</span></h2>
<p>循環参照が発生する具体的なコードを書いてみます。</p>
<h3><span id="toc3">ファイル構成</span></h3>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-plain" data-lang=""><code>./app
├─ a/a.go
├─ b/b.go
├─ main.go
└─ go.mod</code></pre>
</div>
<h3><span id="toc4">go.mod</span></h3>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-go" data-lang="go.mod"><code>module app

go 1.19</code></pre>
</div>
<h3><span id="toc5">main.go</span></h3>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-go" data-lang="main.go"><code>package main

import (
  "app/a"
)

func main() {
  a.CallB()
}
</code></pre>
</div>
<p>&nbsp;</p>
<h3><span id="toc6">a.go</span></h3>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-go" data-lang="a.go"><code>package a

import (
  "fmt"
  "app/b"
)

func PrintA() {
  fmt.Println("A")
}

func CallB() {
  b.PrintB()
}</code></pre>
</div>
<p>&nbsp;</p>
<h3><span id="toc7">b.go</span></h3>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-go" data-lang="b.go"><code>package b

import (
  "fmt"
  "app/a"
)

func PrintB() {
  fmt.Println("B")
}

func CallA() {
  a.PrintA()
}</code></pre>
</div>
<h2><span id="toc8">main.goを実行してみる</span></h2>
<p>この状態で<code>main.go</code>を実行すると<code>import cycle not allowed</code>のエラーが出ます。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>% go run main.go
package command-line-arguments
        imports app/a
        imports app/b
        imports app/a: import cycle not allowed</code></pre>
</div>
<h2><span id="toc9">循環参照の対策方法</span></h2>
<p>&nbsp;</p>
<p>循環参照が起きないようにするには主に下記の方法があるようです。</p>
<ul>
<li><strong>ファイル構成を変更する</strong></li>
<li><strong>interfaceを使う</strong></li>
<li><strong>同じpackageにまとめる</strong></li>
</ul>
<p>それぞれの具体的な実装例はまた別の記事で紹介しようと思います。</p><p>The post <a href="https://shungoblog.com/programming/go-import-cycle-not-allowed.html">【Go】 import cycle not allowed (循環参照)について</a> first appeared on <a href="https://shungoblog.com">shungo blog</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://shungoblog.com/programming/go-import-cycle-not-allowed.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【Docker】 Go × Mailhog × net/smtpでメール送信する</title>
		<link>https://shungoblog.com/programming/docker-go-mailhog-net-smtp.html</link>
					<comments>https://shungoblog.com/programming/docker-go-mailhog-net-smtp.html#respond</comments>
		
		<dc:creator><![CDATA[しゅんご]]></dc:creator>
		<pubDate>Wed, 22 Feb 2023 14:11:45 +0000</pubDate>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[go]]></category>
		<category><![CDATA[mailhog]]></category>
		<guid isPermaLink="false">https://shungoblog.com/?p=1967</guid>

					<description><![CDATA[<p>目次 はじめにコードファイル構成Dockerfiledocker-compose.ymlmain.goメール送信コンテナに入りmain.goを実行mailhogで送信されたメールを確認 はじめに Docker環境で構築し [&#8230;]</p>
<p>The post <a href="https://shungoblog.com/programming/docker-go-mailhog-net-smtp.html">【Docker】 Go × Mailhog × net/smtpでメール送信する</a> first appeared on <a href="https://shungoblog.com">shungo blog</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-16" checked><label class="toc-title" for="toc-checkbox-16">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">はじめに</a></li><li><a href="#toc2" tabindex="0">コード</a><ol><li><a href="#toc3" tabindex="0">ファイル構成</a></li><li><a href="#toc4" tabindex="0">Dockerfile</a></li><li><a href="#toc5" tabindex="0">docker-compose.yml</a></li><li><a href="#toc6" tabindex="0">main.go</a></li></ol></li><li><a href="#toc7" tabindex="0">メール送信</a><ol><li><a href="#toc8" tabindex="0">コンテナに入りmain.goを実行</a></li><li><a href="#toc9" tabindex="0">mailhogで送信されたメールを確認</a></li></ol></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p>Docker環境で構築したGoからメール送信する方法をご紹介します。</p>
<p>メールサーバーには、開発環境でメール送信を確認できる<a rel="nofollow noopener external" target="_blank" href="https://github.com/mailhog/MailHog">mailhog</a>を使用します。</p>
<p>メール送信には標準パッケージの<a rel="nofollow noopener external" target="_blank" href="https://pkg.go.dev/net/smtp">net/smtp</a>を用います。</p>
<p>&nbsp;</p>
<p>今回の実装以外にもいろいろ追加していますが、</p>
<p>下記でメール送信を実装しているので参考にしてみてください！</p>

<a rel="nofollow noopener external" target="_blank" href="https://github.com/shungo0525/doker_go" title="GitHub - shungo0525/doker_go" class="blogcard-wrap external-blogcard-wrap a-wrap cf"><div class="blogcard external-blogcard eb-left cf"><div class="blogcard-label external-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail external-blogcard-thumbnail"><img loading="lazy" decoding="async" src="https://shungoblog.com/wp-content/uploads/cocoon-resources/blog-card-cache/803e1b3a18b5f12c742e15f875c82fcb." alt="" class="blogcard-thumb-image external-blogcard-thumb-image" width="320" height="180" /></figure><div class="blogcard-content external-blogcard-content"><div class="blogcard-title external-blogcard-title">GitHub - shungo0525/doker_go</div><div class="blogcard-snippet external-blogcard-snippet">Contribute to shungo0525/doker_go development by creating an account on GitHub.</div></div><div class="blogcard-footer external-blogcard-footer cf"><div class="blogcard-site external-blogcard-site"><div class="blogcard-favicon external-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://github.com/shungo0525/doker_go" alt="" class="blogcard-favicon-image external-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain external-blogcard-domain">github.com</div></div></div></div></a>
<p>&nbsp;</p>
<h2><span id="toc2">コード</span></h2>
<h3><span id="toc3">ファイル構成</span></h3>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-plain" data-lang=""><code>./root_dir
├─ app
│   ├─ main.go
│   ├─ go.mod
│   └─ go.sum
├─ docker-compose.yml
└─ Dockerfile</code></pre>
</div>
<h3><span id="toc4">Dockerfile</span></h3>
<p>とりあえずGoが使える環境を構築します。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-plain" data-lang="Dockerfile"><code>FROM golang:1.19-alpine

RUN apk update &amp;&amp; apk add git

# appディレクトリの作成
RUN mkdir /go/src/app
# ワーキングディレクトリの設定
WORKDIR /go/src/app</code></pre>
</div>
<h3><span id="toc5">docker-compose.yml</span></h3>
<p>開発環境用のメールサーバーであるmailhogを使用します。</p>
<p>service名の<strong>mailhog</strong>とSMPTポートである<strong>1025</strong>はメール送信するときに指定します。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-yaml" data-lang="docker-compose.yml"><code>version: '3'
services:
  app:
    build: .
    tty: true
    volumes:
      - ./app:/go/src/app
    depends_on:
      - mysql
    ports:
      - 8000:8000

  mailhog:
    image: mailhog/mailhog:latest
    ports:
      - "8025:8025" # MailhogのWebとAPI用のポート
      - "1025:1025" # SMTPポート</code></pre>
</div>
<p>&nbsp;</p>
<h3><span id="toc6">main.go</span></h3>
<p><code>docker-compose.yml</code>で指定したservice名の<strong>mailhog</strong>をhostnameに、portを<strong>1025</strong>に指定します。</p>
<p><code>docker-compose.yml</code>の値とここで指定する値が異なるとメール送信できないので注意しましょう。</p>
<p>送信元、送信先、メッセージ内容は必要に応じて変更してください。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-go" data-lang="main.go"><code>package main

import (
  "fmt"
  "net/smtp"
  "os"
  "strings"
)

var (
  hostname = "mailhog" // docker-composeで指定したサービス名
  port     = 1025 // mailhogのSMPTポート
  username = "user@example.com"
  password = "password"
  from     = "from@example.net"
  subject  = "hello"
  body     = "Hello World!"
  receiver = []string{"receiver@example.com"}
)

func main() {
  SendEmail()
}

func SendEmail() {
  smtpServer := fmt.Sprintf("%s:%d", hostname, port)
  auth := smtp.CRAMMD5Auth(username, password)
  msg := []byte(fmt.Sprintf("To: %s\nSubject: %s\n\n%s", strings.Join(receiver, ","), subject, body))

  if err := smtp.SendMail(smtpServer, auth, from, receiver, msg); err != nil {
    fmt.Fprintln(os.Stderr, err)
  }
}</code></pre>
</div>
<h2><span id="toc7">メール送信</span></h2>
<h3><span id="toc8">コンテナに入りmain.goを実行</span></h3>
<p>コンテナに入って<code>main.go</code>を実行することで、<code>SendEmail()</code>が実行されメール送信されます。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>% dc exec app sh
# go run main.go</code></pre>
</div>
<h3><span id="toc9">mailhogで送信されたメールを確認</span></h3>
<p><a rel="nofollow noopener external" target="_blank" href="http://localhost:8025/">http://localhost:8025/</a>を開くとMailhogでローカル環境で送信したメールを確認することができます。</p>
<p><img loading="lazy" decoding="async" src="https://shungoblog.com/wp-content/uploads/2023/02/スクリーンショット-2023-02-22-23.07.37-300x88.jpg" alt="go-mail-1" width="955" height="280" class="alignnone wp-image-1976" srcset="https://shungoblog.com/wp-content/uploads/2023/02/スクリーンショット-2023-02-22-23.07.37-300x88.jpg 300w, https://shungoblog.com/wp-content/uploads/2023/02/スクリーンショット-2023-02-22-23.07.37-1024x300.jpg 1024w, https://shungoblog.com/wp-content/uploads/2023/02/スクリーンショット-2023-02-22-23.07.37-768x225.jpg 768w, https://shungoblog.com/wp-content/uploads/2023/02/スクリーンショット-2023-02-22-23.07.37-1536x450.jpg 1536w, https://shungoblog.com/wp-content/uploads/2023/02/スクリーンショット-2023-02-22-23.07.37.jpg 1920w" sizes="(max-width: 955px) 100vw, 955px" /></p>
<p>クリックすると送信内容の詳細を確認することができます。</p>
<p>&nbsp;</p>
<p><img loading="lazy" decoding="async" src="https://shungoblog.com/wp-content/uploads/2023/02/スクリーンショット-2023-02-22-23.07.41-300x88.jpg" alt="go-mail-2" width="1285" height="377" class="alignnone wp-image-1977" srcset="https://shungoblog.com/wp-content/uploads/2023/02/スクリーンショット-2023-02-22-23.07.41-300x88.jpg 300w, https://shungoblog.com/wp-content/uploads/2023/02/スクリーンショット-2023-02-22-23.07.41-1024x300.jpg 1024w, https://shungoblog.com/wp-content/uploads/2023/02/スクリーンショット-2023-02-22-23.07.41-768x225.jpg 768w, https://shungoblog.com/wp-content/uploads/2023/02/スクリーンショット-2023-02-22-23.07.41-1536x450.jpg 1536w, https://shungoblog.com/wp-content/uploads/2023/02/スクリーンショット-2023-02-22-23.07.41.jpg 1920w" sizes="(max-width: 1285px) 100vw, 1285px" /></p><p>The post <a href="https://shungoblog.com/programming/docker-go-mailhog-net-smtp.html">【Docker】 Go × Mailhog × net/smtpでメール送信する</a> first appeared on <a href="https://shungoblog.com">shungo blog</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://shungoblog.com/programming/docker-go-mailhog-net-smtp.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Docker × Go で gRPC を動かしてみた</title>
		<link>https://shungoblog.com/programming/docker-go-grpc.html</link>
					<comments>https://shungoblog.com/programming/docker-go-grpc.html#respond</comments>
		
		<dc:creator><![CDATA[しゅんご]]></dc:creator>
		<pubDate>Mon, 13 Feb 2023 13:05:14 +0000</pubDate>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[go]]></category>
		<category><![CDATA[grpc]]></category>
		<guid isPermaLink="false">https://shungoblog.com/?p=1781</guid>

					<description><![CDATA[<p>目次 はじめにローカル環境で実行する場合パッケージインストールディレクトリ構成protoファイル作成protocコマンドでコードを自動生成gRPCサーバーを作成gRPCurlをインストールgRPCサーバーを起動gRPCク [&#8230;]</p>
<p>The post <a href="https://shungoblog.com/programming/docker-go-grpc.html">Docker × Go で gRPC を動かしてみた</a> first appeared on <a href="https://shungoblog.com">shungo blog</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-18" checked><label class="toc-title" for="toc-checkbox-18">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">はじめに</a></li><li><a href="#toc2" tabindex="0">ローカル環境で実行する場合</a><ol><li><a href="#toc3" tabindex="0">パッケージインストール</a></li><li><a href="#toc4" tabindex="0">ディレクトリ構成</a></li><li><a href="#toc5" tabindex="0">protoファイル作成</a></li><li><a href="#toc6" tabindex="0">protocコマンドでコードを自動生成</a></li><li><a href="#toc7" tabindex="0">gRPCサーバーを作成</a></li><li><a href="#toc8" tabindex="0">gRPCurlをインストール</a></li><li><a href="#toc9" tabindex="0">gRPCサーバーを起動</a></li><li><a href="#toc10" tabindex="0">gRPCクライアントを作成</a></li><li><a href="#toc11" tabindex="0">クライアントを実行して動作確認</a></li></ol></li><li><a href="#toc12" tabindex="0">Docker環境で実行する場合</a><ol><li><a href="#toc13" tabindex="0">Dockerfile</a></li><li><a href="#toc14" tabindex="0">docker-compose.yml</a></li><li><a href="#toc15" tabindex="0">Docker環境で実行する</a></li></ol></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p>この記事では<strong>go × gRPC</strong>で簡単なリクエスト送信・レスポンスの表示を説明していきます。</p>
<p>大きく分けて、下記の3つを順番に実行していきます。</p>
<ul>
<li>protoファイルからコードを自動生成</li>
<li>goでgRPCサーバーを起動</li>
<li>goでクライアントを実行してリクエスト送信・レスポンス表示</li>
</ul>
<p>最初はローカルで実行して、次に同じことをDocker環境でも実行します。</p>
<p>&nbsp;</p>
<p>この記事を書くにあたり、下記を参考にさせていただきました。</p>
<p>参考: <a rel="nofollow noopener external" target="_blank" href="https://zenn.dev/hsaki/books/golang-grpc-starting/viewer">作ってわかる！ はじめてのgRPC</a></p>
<p>&nbsp;</p>
<p>今回実装したリポジトリです。</p>
<p>全体のコードはこちらをご覧くだしさい。</p>

<a rel="nofollow noopener external" target="_blank" href="https://github.com/shungo0525/grpc" title="GitHub - shungo0525/grpc" class="blogcard-wrap external-blogcard-wrap a-wrap cf"><div class="blogcard external-blogcard eb-left cf"><div class="blogcard-label external-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail external-blogcard-thumbnail"><img loading="lazy" decoding="async" src="https://shungoblog.com/wp-content/uploads/cocoon-resources/blog-card-cache/5f8b70b73a9dc0d396e83d28d911d91d." alt="" class="blogcard-thumb-image external-blogcard-thumb-image" width="320" height="180" /></figure><div class="blogcard-content external-blogcard-content"><div class="blogcard-title external-blogcard-title">GitHub - shungo0525/grpc</div><div class="blogcard-snippet external-blogcard-snippet">Contribute to shungo0525/grpc development by creating an account on GitHub.</div></div><div class="blogcard-footer external-blogcard-footer cf"><div class="blogcard-site external-blogcard-site"><div class="blogcard-favicon external-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://github.com/shungo0525/grpc" alt="" class="blogcard-favicon-image external-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain external-blogcard-domain">github.com</div></div></div></div></a>
<h2><span id="toc2">ローカル環境で実行する場合</span></h2>
<h3><span id="toc3">パッケージインストール</span></h3>
<p>まずは必要なパッケージをインストールします。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>$ brew install protobuf
$ go get -u google.golang.org/grpc
$ go get -u google.golang.org/grpc/cmd/protoc-gen-go-grpc</code></pre>
</div>
<p>パッケージの依存関係を管理するためのgo.modファイルを生成します。</p>
<p>&nbsp;</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>$ cd s<span>tudy_grpc # 作業ディレクトリ
</span>$ go mod init mygrpc</code></pre>
</div>
<h3><span id="toc4">ディレクトリ構成</span></h3>
<p>今回は下記のようなディレクトリ構成にしました。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-plain" data-lang=""><code><span>./study_grpc # 作業ルートディレクトリ
├─ api
│   └─ hello.proto # protoファイル
<span class="token unchanged">├─ cmd
│   ├─ server
│   │ └─ main.<span class="hljs-keyword">go</span>
</span><span class="token inserted-sign inserted">│   └─ client
│    <span class="token unchanged">    </span>└─ main.<span class="hljs-keyword">go</span></span>
├─ pkg
│   └─ grpc # ここにコードを自動生成させる
│         ├─ hello.pb.<span class="hljs-keyword">go</span>
│         └─ hello_grpc.pb.<span class="hljs-keyword">go</span>
├─ <span class="hljs-keyword">go</span>.mod
└─ <span class="hljs-keyword">go</span>.sum</span></code></pre>
</div>
<p>&nbsp;</p>
<h3><span id="toc5">protoファイル作成</span></h3>
<p><code><strong>api/hello.proto</strong></code></p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-plain" data-lang=""><code><span><span class="hljs-comment">// protoのバージョンの宣言</span>
</span><span>syntax</span>= <span><span class="hljs-string">"proto3"</span></span><span>;
</span><span>
</span><span><span class="hljs-comment">// protoファイルから自動生成させるGoのコードの置き先</span>
</span><span><span class="hljs-comment">// (詳細は4章にて)</span>
</span><span>option </span>go_package = <span><span class="hljs-string">"pkg/grpc"</span></span><span>;
</span><span>
</span><span><span class="hljs-comment">// packageの宣言</span>
</span><span><span class="hljs-keyword">package</span> </span>myapp<span>;
</span><span>
</span><span><span class="hljs-comment">// サービスの定義</span>
</span><span>service </span>GreetingService {
   <span><span class="hljs-comment">// サービスが持つメソッドの定義</span>
</span><span>  </span><span><span class="hljs-function">rpc </span></span><span class="hljs-function"><span class="hljs-title">Hello</span> <span class="hljs-params">(HelloRequest)</span> </span><span><span class="hljs-function"><span class="hljs-title">returns</span> </span></span><span class="hljs-function"><span class="hljs-params">(HelloResponse)</span></span><span>;
</span>}

<span><span class="hljs-comment">// 型の定義</span>
</span><span>message </span>HelloRequest {
   <span>string</span>name = <span><span class="hljs-number">1</span></span><span>;
</span>}

<span>message </span>HelloResponse {
   <span>string</span>message = <span><span class="hljs-number">1</span></span><span>;
</span>}</code></pre>
</div>
<p>&nbsp;</p>
<h3><span id="toc6">protocコマンドでコードを自動生成</span></h3>
<p>下記のコマンドを実行すると<code>pkg/grpc</code><span>ディレクトリ直下に、2つのファイルが生成されます。</span></p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code><span><span class="hljs-meta">$  </span></span><span class="token builtin class-name"><span class="bash"><span class="hljs-built_in">cd</span></span></span><span><span class="bash"> api
</span><span class="hljs-meta">$</span><span class="bash"> protoc </span></span><span class="token parameter variable"><span class="bash">--go_out</span></span><span class="token operator"><span class="bash">=</span></span><span class="token punctuation"><span class="bash">..</span></span><span><span class="bash">/pkg/grpc </span></span><span class="token parameter variable"><span class="bash">--go_opt</span></span><span class="token operator"><span class="bash">=</span></span><span><span class="bash">paths</span></span><span class="token operator"><span class="bash">=</span></span><span><span class="bash">source_relative </span></span><span class="token punctuation"><span class="bash">\
</span></span><span>         --go-grpc_out</span><span class="token operator">=</span><span class="token punctuation">..</span><span>/pkg/grpc --go-grpc_opt</span><span class="token operator">=</span><span>paths</span><span class="token operator">=</span><span>source_relative </span><span class="token punctuation">\
</span><span>         hello.proto</span></code></pre>
</div>
<p>&nbsp;</p>
<p><strong><code><span class="token parameter variable">--go_opt</span><span class="token operator">=</span>paths<span class="token operator">=</span>source_relative</code></strong>は相対パスを指定するオプションです。</p>
<p><strong><code>./study_grpc/api</code></strong>でコマンドを実行したため、相対パスでファイルの保存先を指定しています。</p>
<p>&nbsp;</p>
<p>ちなみに<strong><code><span class="token parameter variable">--go_opt</span><span class="token operator">=</span>paths<span class="token operator">=</span>source_relative</code></strong>を使わず、<strong><code>./study_grpc/</code></strong>から実行する場合は、</p>
<p>下記のコマンドになります。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code><span>$ protoc --go_out=./ --go-grpc_out=./ api/hello.proto</span></code></pre>
</div>
<p>&nbsp;</p>
<h3><span id="toc7">gRPCサーバーを作成</span></h3>
<p><code><strong>cmd/server/main.go</strong></code></p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-go" data-lang="Go"><code>package main

import (
  "fmt"
  "net"
  "log"
  "os"
  "context"
  "os/signal"
  "google.golang.org/grpc"
  "google.golang.org/grpc/reflection"
  hellopb "mygrpc/pkg/grpc"
)

func NewMyServer() *myServer {
  return &amp;myServer{}
}

func main() {
  // 1. 8080番portのLisnterを作成
  port := 8080
  listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
  if err != nil {
    panic(err)
  }

  // 2. gRPCサーバーを作成
  s := grpc.NewServer()

  // 3. gRPCサーバーにGreetingServiceを登録
  hellopb.RegisterGreetingServiceServer(s, NewMyServer())

  // 4. サーバーリフレクションの設定
  reflection.Register(s)

  // 5. 作成したgRPCサーバーを、8080番ポートで稼働させる
  go func() {
    log.Printf("start gRPC server port: %v", port)
    s.Serve(listener)
  }()

  // 6.Ctrl+Cが入力されたらGraceful shutdownされるようにする
  quit := make(chan os.Signal, 1)
  signal.Notify(quit, os.Interrupt)
  &lt;-quit
  log.Println("stopping gRPC server...")
  s.GracefulStop()
}

type myServer struct {
  hellopb.UnimplementedGreetingServiceServer
}

func (s *myServer) Hello(ctx context.Context, req *hellopb.HelloRequest) (*hellopb.HelloResponse, error) {
  // リクエストからnameフィールドを取り出して
  // "Hello, [名前]!"というレスポンスを返す
  return &amp;hellopb.HelloResponse{
    Message: fmt.Sprintf("Hello, %s!", req.GetName()),
  }, nil
}</code></pre>
</div>
<p>&nbsp;</p>
<h3><span id="toc8">gRPCurlをインストール</span></h3>
<p>gPRCはcurlで動作確認できませんが、gPRCurlを使うことで,</p>
<p>ローカル環境でも<span>動作確認することができます。</span></p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code><span>$ brew  </span><span class="token function">install</span><span> grpcurl</span></code></pre>
</div>
<p>&nbsp;</p>
<h3><span id="toc9">gRPCサーバーを起動</span></h3>
<p>これでgRPCサーバーを起動する準備ができました！</p>
<p>下記コマンドを実行してgRPCが起動すれば成功です！</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code><span>$ go cmd/server/run main.go
</span>2023/02/13 10:01:38 start gRPC server port: 8080</code></pre>
</div>
<p>&nbsp;</p>
<h3><span id="toc10">gRPCクライアントを作成</span></h3>
<p><strong>cmd/server/main.go</strong></p>
<p>&nbsp;</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-go" data-lang="Go"><code>package main

import (
  "bufio"
  "fmt"
  "os"
  "log"
  "context"
  "google.golang.org/grpc"
  "google.golang.org/grpc/credentials/insecure"
  hellopb "mygrpc/pkg/grpc"
)

var (
  scanner *bufio.Scanner
  client  hellopb.GreetingServiceClient
)

func main() {
  fmt.Println("start gRPC Client.")

  // 1. 標準入力から文字列を受け取るスキャナを用意
  scanner = bufio.NewScanner(os.Stdin)

  // 2. gRPCサーバーとのコネクションを確立
  address := "localhost:8080"
  conn, err := grpc.Dial(
    address,

    grpc.WithTransportCredentials(insecure.NewCredentials()),
    grpc.WithBlock(),
  )
  if err != nil {
    log.Fatal("Connection failed.")
    return
  }
  defer conn.Close()

  // 3. gRPCクライアントを生成
  client = hellopb.NewGreetingServiceClient(conn)

  for {
    fmt.Println("1: send Request")
    fmt.Println("2: exit")
    fmt.Print("please enter &gt;")

    scanner.Scan()
    in := scanner.Text()

    switch in {
    case "1":
      Hello()

    case "2":
      fmt.Println("bye.")
      goto M
    }
  }
M:
}

func Hello() {
  fmt.Println("Please enter your name.")
  scanner.Scan()
  name := scanner.Text()

  req := &amp;hellopb.HelloRequest{
    Name: name,
  }
  res, err := client.Hello(context.Background(), req)
  if err != nil {
    fmt.Println(err)
  } else {
    fmt.Println(res.GetMessage())
  }
}</code></pre>
</div>
<p>&nbsp;</p>
<h3><span id="toc11">クライアントを実行して動作確認</span></h3>
<p>gRPCサーバーとは別のターミナルを開いて、下記を実行することで、</p>
<p>gPRCサーバーに対して、リクエスト送信・レスポンス表示をすることができます。<span style="background-color: #e9ebec; color: inherit; font-family: inherit; font-size: var(--hcb-font-size,14px); white-space: pre;"></span></p>
<div class="hcb_wrap">
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code><span>$ go run cmd/client/main.go
start gRPC Client.

</span><span class="token number">1</span><span>: Hello
</span><span class="token number">2</span><span>: </span><span class="token builtin class-name">exit </span><span>please enter </span><span class="token operator">&gt;</span><span class="token number">1

</span><span>Please enter your name.
shungo
Hello, shungo</span><span class="token operator">!</span><span class="token number">

1</span><span>: Hello
</span><span class="token number">2</span><span>: </span><span class="token builtin class-name">exit </span><span>please enter</span><span> </span><span class="token operator">&gt;</span><span class="token number">2
</span><span>bye.</span></code></pre>
</div>
</div>
<p><span>このように、リクエスト送信・レスポンスの表示ができれば成功です！</span></p>
<p>&nbsp;</p>
<h2><span id="toc12">Docker環境で実行する場合</span></h2>
<p>これまではローカル環境にパッケージをインストールして、ローカル環境でgRPC用のコードを生成していました。</p>
<p>gRPC入門の記事を見るとローカルで実行するものが多いですが、バージョン管理などを考慮したらやはりDocker環境で実行したいですよね。</p>
<p>そこで、これまでやってきたことを今後はDocker環境で実行してみようと思います。</p>
<p>&nbsp;</p>
<h3><span id="toc13">Dockerfile</span></h3>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-docker" data-lang="docker"><code>FROM golang:1.19.5-buster

ENV PROTOBUF_VERSION3.17.3

RUN apt-getupdate \
    &amp;&amp; apt-getinstall -y protobuf-compiler unzip --no-install-recommends \
    &amp;&amp; apt-getclean \
    &amp;&amp; rm-rf /var/lib/apt/lists/*

WORKDIR /grpc
COPY. /grpc

## build時のみ使いたいので、runで実行。
RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
RUN go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
RUN go get google.golang.org/grpc/internal/channelz@v1.53.0</code></pre>
</div>
<p>&nbsp;</p>
<h3><span id="toc14">docker-compose.yml</span></h3>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-yaml" data-lang="docker-compose.yml"><code>version:'3'

services:
  grpc:
    build: .
    volumes:
      - .:/grpc
    ports:
      - "8080:8080"
   tty: true</code></pre>
</div>
<p>&nbsp;</p>
<h3><span id="toc15">Docker環境で実行する</span></h3>
<p>1つ目のターミナルでdocker-composeを起動します。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>$ docker-compose up</code></pre>
</div>
<p>2つ目のターミナルでコンテナに入り、gRPCサーバーを起動します。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>$ docker-compose exec grpc bash
&gt; go run cmd/server/main.go
2023/02/13 10:01:38 start gRPC server port: 8080
</code></pre>
</div>
<p>3つ目のターミナルでコンテナに入り、クライアントを動かします。</p>
<p>&nbsp;</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-bash" data-lang="Bash"><code>$ docker-compose exec grpc bash
&gt; go run cmd/client/main.go
<span class="token number"><span class="hljs-attr">1</span></span><span>: <span class="hljs-string">Hello
</span></span><span class="token number"><span class="hljs-attr">2</span></span><span>:</span><span class="token builtin class-name"><span class="hljs-string">exit
</span></span><span><span class="hljs-attr">please</span> <span class="hljs-string">enter</span></span><span class="token operator"><span class="hljs-string">&gt;</span></span><span class="token number"><span class="hljs-string">1

</span></span><span><span class="hljs-attr">Please</span> <span class="hljs-string">enter your name.
</span><span class="hljs-attr">shungo
</span><span class="hljs-meta">Hello,</span> <span class="hljs-string">shungo!

</span></span><span class="token number"><span class="hljs-attr">1</span></span><span>: <span class="hljs-string">Hello
</span></span><span class="token number"><span class="hljs-attr">2</span></span><span>:</span><span class="token builtin class-name"><span class="hljs-string">exit
</span></span><span><span class="hljs-attr">please</span> <span class="hljs-string">enter</span></span><span class="token operator"><span class="hljs-string">&gt;</span></span><span class="token number"><span class="hljs-string">2

</span></span><span><span class="hljs-attr">bye.</span></span></code></pre>
</div>
<p>これでDocker環境でもgRPCを動かせることを確認できました！</p>
<p>上記では実行していませんが、コンテナ内で同じようにprotocコマンドでコードを生成することも可能です。</p><p>The post <a href="https://shungoblog.com/programming/docker-go-grpc.html">Docker × Go で gRPC を動かしてみた</a> first appeared on <a href="https://shungoblog.com">shungo blog</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://shungoblog.com/programming/docker-go-grpc.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【React Native】 3点リーダーで文字を省略する方法</title>
		<link>https://shungoblog.com/programming/reactnative-3dotted-reader.html</link>
					<comments>https://shungoblog.com/programming/reactnative-3dotted-reader.html#respond</comments>
		
		<dc:creator><![CDATA[しゅんご]]></dc:creator>
		<pubDate>Tue, 31 Jan 2023 09:58:41 +0000</pubDate>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[react-native]]></category>
		<category><![CDATA[エンジニア]]></category>
		<guid isPermaLink="false">https://shungoblog.com/?p=1726</guid>

					<description><![CDATA[<p>&#160; 目次 ReactNativeの3点リーダーnumberOfLinesellipsizeMode参考URL普通のcssの場合 ReactNativeの3点リーダー Textで”numberOfLines”と” [&#8230;]</p>
<p>The post <a href="https://shungoblog.com/programming/reactnative-3dotted-reader.html">【React Native】 3点リーダーで文字を省略する方法</a> first appeared on <a href="https://shungoblog.com">shungo blog</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>&nbsp;</p>

  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-20" checked><label class="toc-title" for="toc-checkbox-20">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">ReactNativeの3点リーダー</a><ol><li><a href="#toc2" tabindex="0">numberOfLines</a></li><li><a href="#toc3" tabindex="0">ellipsizeMode</a></li><li><a href="#toc4" tabindex="0">参考URL</a></li></ol></li><li><a href="#toc5" tabindex="0">普通のcssの場合</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">ReactNativeの3点リーダー</span></h2>
<p>Textで”<span>numberOfLines”と”ellipsizeMode”を指定することで3点リーダーを表示することができます。</span></p>
<p>下記が使用例です。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-js" data-lang="JavaScript"><code></code><code><span>&lt;Text </span><span>numberOfLines</span><span>=</span>{<span>1</span>} <span>ellipsizeMode</span><span>="tail"</span><span>&gt;
 </span> <span>abcdefghijklmnopqrstuvwxyz
</span><span>&lt;/Text&gt;</span></code></pre>
</div>
<p>&nbsp;</p>
<h3><span id="toc2"><span>numberOfLines</span></span></h3>
<p>省略せずに表示する行数です。</p>
<p><span>numberOfLines</span><span>=</span>{<span>1</span>}の場合、1行目は表示して、2行以降になる部分を3点リーダーで省略します。</p>
<h3><span id="toc3"><span>ellipsizeMode</span></span></h3>
<p>省略するときの表示方法を指定します。</p>
<div class="scrollable-table"><table style="border-collapse: collapse; width: 100%; height: 210px;">
<tbody>
<tr style="height: 42px;">
<td style="width: 33.3333%; height: 42px;"><strong>numberOfLines</strong></td>
<td style="width: 33.3333%; height: 42px;"><strong>詳細</strong></td>
<td style="width: 33.3333%; height: 42px;"><strong>表示例</strong></td>
</tr>
<tr style="height: 42px;">
<td style="width: 33.3333%; height: 42px;">head</td>
<td style="width: 33.3333%; height: 42px;">末尾がコンテナに収まるように表示され、行の先頭のテキストは省略記号で示されます。</td>
<td style="width: 33.3333%; height: 42px;"><span>&#8230;wxyz</span></td>
</tr>
<tr style="height: 42px;">
<td style="width: 33.3333%; height: 42px;">middle</td>
<td style="width: 33.3333%; height: 42px;"><span>先頭と末尾がコンテナーに収まるように表示され、途中が省略記号で示されます。</span></td>
<td style="width: 33.3333%; height: 42px;"><span>ab&#8230;yz</span></td>
</tr>
<tr style="height: 42px;">
<td style="width: 33.3333%; height: 42px;">tail (よく使用する)</td>
<td style="width: 33.3333%; height: 42px;"><span>先頭がコンテナーに収まるように行が表示され、末尾が省略記号で示されます。</span></td>
<td style="width: 33.3333%; height: 42px;"><span>abcd&#8230;</span></td>
</tr>
<tr style="height: 42px;">
<td style="width: 33.3333%; height: 42px;">clip</td>
<td style="width: 33.3333%; height: 42px;"><span>コンテナに収まらない文字は表示されません。</span></td>
<td style="width: 33.3333%; height: 42px;">abcde</td>
</tr>
</tbody>
</table></div>
<p>&nbsp;</p>
<h3><span id="toc4">参考URL</span></h3>

<a rel="nofollow noopener external" target="_blank" href="https://reactnative.dev/docs/text#ellipsizemode" title="Text · React Native" class="blogcard-wrap external-blogcard-wrap a-wrap cf"><div class="blogcard external-blogcard eb-left cf"><div class="blogcard-label external-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail external-blogcard-thumbnail"><img loading="lazy" decoding="async" src="https://shungoblog.com/wp-content/uploads/cocoon-resources/blog-card-cache/ef223cf76396449f77ab357128a21e16.png" alt="" class="blogcard-thumb-image external-blogcard-thumb-image" width="320" height="180" /></figure><div class="blogcard-content external-blogcard-content"><div class="blogcard-title external-blogcard-title">Text · React Native</div><div class="blogcard-snippet external-blogcard-snippet">A React component for displaying text.</div></div><div class="blogcard-footer external-blogcard-footer cf"><div class="blogcard-site external-blogcard-site"><div class="blogcard-favicon external-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://reactnative.dev/docs/text#ellipsizemode" alt="" class="blogcard-favicon-image external-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain external-blogcard-domain">reactnative.dev</div></div></div></div></a>
<p>&nbsp;</p>
<h2><span id="toc5">普通のcssの場合</span></h2>
<p>ちなみにReact NativeでなくCSSで書く場合は下記のCSSで3点リーダーは実装可能です。</p>
<div class="hcb_wrap">
<pre class="prism line-numbers lang-css" data-lang="CSS"><code><span class="hljs-attribute">display</span><span>: -webkit-box;</span>
<span class="hljs-attribute">-webkit-box-orient</span><span>: vertical;</span>
<span class="hljs-attribute">-webkit-line-clamp</span><span>: </span><span class="hljs-number">3;</span>
<span class="hljs-attribute">overflow</span>: hidden;</code></pre>
</div><p>The post <a href="https://shungoblog.com/programming/reactnative-3dotted-reader.html">【React Native】 3点リーダーで文字を省略する方法</a> first appeared on <a href="https://shungoblog.com">shungo blog</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://shungoblog.com/programming/reactnative-3dotted-reader.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
