<?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/"
	xmlns:series="https://publishpress.com/"
	>

<channel>
	<title>Ruby On Rails Archives - Tomoshare</title>
	<atom:link href="https://blog.tomosia.com.vn/tag/ruby-on-rails/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.tomosia.com.vn/tag/ruby-on-rails/</link>
	<description>Kênh chia sẻ kiến thức Tomosia Việt Nam</description>
	<lastBuildDate>Thu, 18 Jan 2024 01:46:01 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://blog.tomosia.com.vn/wp-content/uploads/2023/09/cropped-icon-32x32.png</url>
	<title>Ruby On Rails Archives - Tomoshare</title>
	<link>https://blog.tomosia.com.vn/tag/ruby-on-rails/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>[Rails Tips] Rails 7.1 &#8211; ActiveRecord::QueryMethods#select has added support for hash values</title>
		<link>https://blog.tomosia.com.vn/rails-tips-rails-7-1-activerecordquerymethodsselect-has-added-support-for-hash-values/</link>
					<comments>https://blog.tomosia.com.vn/rails-tips-rails-7-1-activerecordquerymethodsselect-has-added-support-for-hash-values/#comments</comments>
		
		<dc:creator><![CDATA[Thuan Nguyen Van]]></dc:creator>
		<pubDate>Thu, 18 Jan 2024 01:45:59 +0000</pubDate>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[ActiveRecord]]></category>
		<category><![CDATA[Ruby On Rails]]></category>
		<category><![CDATA[Rails7.1]]></category>
		<guid isPermaLink="false">https://blog.tomosia.com.vn/?p=3011</guid>

					<description><![CDATA[<p>Trong bản cập nhật mới nhất của, Rails 7.1 đã cho phép chúng ta query select theo giá&#8230;</p>
<p>The post <a href="https://blog.tomosia.com.vn/rails-tips-rails-7-1-activerecordquerymethodsselect-has-added-support-for-hash-values/">[Rails Tips] Rails 7.1 &#8211; ActiveRecord::QueryMethods#select has added support for hash values</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Trong bản cập nhật mới nhất của, Rails 7.1 đã cho phép chúng ta query <strong>select</strong> theo giá trị hash chứ không cần phải sử dụng <strong>raw SQL</strong> nữa.</p>



<p>💎 Improvements:<br>1️⃣ New support query với giá trị <strong>Hash</strong><br>2️⃣ Chúng ta không cần phải dùng truy vấn <strong>raw version</strong> nữa</p>



<p>💎 Bonus:<br>1️⃣ Cú pháp mới cũng support chúng ta sử dụng <strong>alias</strong><br>2️⃣ Sử dụng tương tự cho ActiveRecord#reselect</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Ruby</span><span role="button" tabindex="0" data-code="# Before Rails 7.1

Post.joins(:comments)
    .select(
      &quot;posts.id as post_id, posts.title as post_title,
      comments.id as comment_id, comments.body as comment_body&quot;
    )
    
Post.joins(:comments).select(:id, :title, &quot;comments.body&quot;)

# After Rails 7.1

Post.joins(:comments)
    .select(
      posts: { id: :post_id, title: :post_title },
      comments: { id: :comments_id, body: :comment_body }
    )
    
Post.joins(:comments).select(:id, :title, comments: [:body] )" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #7B7F8B"># Before Rails 7.1</span></span>
<span class="line"></span>
<span class="line"><span style="color: #97E1F1; font-style: italic">Post</span><span style="color: #F6F6F4">.joins(</span><span style="color: #BF9EEE">:comments</span><span style="color: #F6F6F4">)</span></span>
<span class="line"><span style="color: #F6F6F4">    .</span><span style="color: #97E1F1">select</span><span style="color: #F6F6F4">(</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">posts.id as post_id, posts.title as post_title,</span></span>
<span class="line"><span style="color: #E7EE98">      comments.id as comment_id, comments.body as comment_body</span><span style="color: #DEE492">&quot;</span></span>
<span class="line"><span style="color: #F6F6F4">    )</span></span>
<span class="line"><span style="color: #F6F6F4">    </span></span>
<span class="line"><span style="color: #97E1F1; font-style: italic">Post</span><span style="color: #F6F6F4">.joins(</span><span style="color: #BF9EEE">:comments</span><span style="color: #F6F6F4">).</span><span style="color: #97E1F1">select</span><span style="color: #F6F6F4">(</span><span style="color: #BF9EEE">:id</span><span style="color: #F6F6F4">, </span><span style="color: #BF9EEE">:title</span><span style="color: #F6F6F4">, </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">comments.body</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #7B7F8B"># After Rails 7.1</span></span>
<span class="line"></span>
<span class="line"><span style="color: #97E1F1; font-style: italic">Post</span><span style="color: #F6F6F4">.joins(</span><span style="color: #BF9EEE">:comments</span><span style="color: #F6F6F4">)</span></span>
<span class="line"><span style="color: #F6F6F4">    .</span><span style="color: #97E1F1">select</span><span style="color: #F6F6F4">(</span></span>
<span class="line"><span style="color: #F6F6F4">      posts</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> { id</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">:post_id</span><span style="color: #F6F6F4">, title</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">:post_title</span><span style="color: #F6F6F4"> },</span></span>
<span class="line"><span style="color: #F6F6F4">      comments</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> { id</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">:comments_id</span><span style="color: #F6F6F4">, body</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">:comment_body</span><span style="color: #F6F6F4"> }</span></span>
<span class="line"><span style="color: #F6F6F4">    )</span></span>
<span class="line"><span style="color: #F6F6F4">    </span></span>
<span class="line"><span style="color: #97E1F1; font-style: italic">Post</span><span style="color: #F6F6F4">.joins(</span><span style="color: #BF9EEE">:comments</span><span style="color: #F6F6F4">).</span><span style="color: #97E1F1">select</span><span style="color: #F6F6F4">(</span><span style="color: #BF9EEE">:id</span><span style="color: #F6F6F4">, </span><span style="color: #BF9EEE">:title</span><span style="color: #F6F6F4">, comments</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> [</span><span style="color: #BF9EEE">:body</span><span style="color: #F6F6F4">] )</span></span></code></pre></div>



<figure class="wp-block-image size-full"><img fetchpriority="high" decoding="async" width="956" height="551" src="http://blog.tomosia.com.vn/wp-content/uploads/2024/01/Screen-Shot-2024-01-02-at-14.42.49.png" alt="" class="wp-image-3016" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2024/01/Screen-Shot-2024-01-02-at-14.42.49.png 956w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/Screen-Shot-2024-01-02-at-14.42.49-300x173.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/Screen-Shot-2024-01-02-at-14.42.49-768x443.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/Screen-Shot-2024-01-02-at-14.42.49-380x219.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/Screen-Shot-2024-01-02-at-14.42.49-800x461.png 800w" sizes="(max-width: 956px) 100vw, 956px" /></figure>
<p>The post <a href="https://blog.tomosia.com.vn/rails-tips-rails-7-1-activerecordquerymethodsselect-has-added-support-for-hash-values/">[Rails Tips] Rails 7.1 &#8211; ActiveRecord::QueryMethods#select has added support for hash values</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.tomosia.com.vn/rails-tips-rails-7-1-activerecordquerymethodsselect-has-added-support-for-hash-values/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
			</item>
		<item>
		<title>Setup slack notifications in Rails</title>
		<link>https://blog.tomosia.com.vn/setup-slack-notifications-in-rails/</link>
					<comments>https://blog.tomosia.com.vn/setup-slack-notifications-in-rails/#comments</comments>
		
		<dc:creator><![CDATA[NST]]></dc:creator>
		<pubDate>Tue, 26 Dec 2023 02:05:13 +0000</pubDate>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby On Rails]]></category>
		<category><![CDATA[Rails]]></category>
		<guid isPermaLink="false">https://blog.tomosia.com.vn/?p=2766</guid>

					<description><![CDATA[<p>Slack là một phần mềm Worksplace sử dụng thông dụng rộng rãi. Tuy nhiên, ta có thể sử&#8230;</p>
<p>The post <a href="https://blog.tomosia.com.vn/setup-slack-notifications-in-rails/">Setup slack notifications in Rails</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><img decoding="async" width="900" height="182" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/12/6423429367ad4157dea8a421_DUd_u8MT6t1xMJ6uXhHyllmQmHzK6KTyp1c5Xfxk8jmfvnrc-MEkdKAryNdNMD_WJQ5N67JxAVcq5JjFg7Oovf4f3SfthtgdBmmR-wyJETHD1twRYCObfA6aJUzu0xTSR2MB3zCX.png" alt="" class="wp-image-2778" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/12/6423429367ad4157dea8a421_DUd_u8MT6t1xMJ6uXhHyllmQmHzK6KTyp1c5Xfxk8jmfvnrc-MEkdKAryNdNMD_WJQ5N67JxAVcq5JjFg7Oovf4f3SfthtgdBmmR-wyJETHD1twRYCObfA6aJUzu0xTSR2MB3zCX.png 900w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/6423429367ad4157dea8a421_DUd_u8MT6t1xMJ6uXhHyllmQmHzK6KTyp1c5Xfxk8jmfvnrc-MEkdKAryNdNMD_WJQ5N67JxAVcq5JjFg7Oovf4f3SfthtgdBmmR-wyJETHD1twRYCObfA6aJUzu0xTSR2MB3zCX-300x61.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/6423429367ad4157dea8a421_DUd_u8MT6t1xMJ6uXhHyllmQmHzK6KTyp1c5Xfxk8jmfvnrc-MEkdKAryNdNMD_WJQ5N67JxAVcq5JjFg7Oovf4f3SfthtgdBmmR-wyJETHD1twRYCObfA6aJUzu0xTSR2MB3zCX-768x155.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/6423429367ad4157dea8a421_DUd_u8MT6t1xMJ6uXhHyllmQmHzK6KTyp1c5Xfxk8jmfvnrc-MEkdKAryNdNMD_WJQ5N67JxAVcq5JjFg7Oovf4f3SfthtgdBmmR-wyJETHD1twRYCObfA6aJUzu0xTSR2MB3zCX-380x77.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/6423429367ad4157dea8a421_DUd_u8MT6t1xMJ6uXhHyllmQmHzK6KTyp1c5Xfxk8jmfvnrc-MEkdKAryNdNMD_WJQ5N67JxAVcq5JjFg7Oovf4f3SfthtgdBmmR-wyJETHD1twRYCObfA6aJUzu0xTSR2MB3zCX-800x162.png 800w" sizes="(max-width: 900px) 100vw, 900px" /></figure>



<p>Slack là một phần mềm <strong>Worksplace</strong> sử dụng thông dụng rộng rãi. Tuy nhiên, ta có thể sử dụng slack để theo dõi và giám sát hệ thống, gửi tin nhắn tự động.</p>



<p>Sau đây, mình sẽ hướng dẫn mọi người cách để gửi thông báo, tin nhắn … đến slack trong rails app, nó làm cho Rails Application của bạn có thể trở nên năng động và hiệu quả hơn.</p>



<h3 id="setup-slack" class="wp-block-heading"><strong>Setup Slack</strong>:</h3>



<p>Đầu tiên, bạn phải có 1 Worksplace, 1 channel nào đó rồi nhé.</p>



<ul class="wp-block-list">
<li>Bạn cần tạo một App Slack từ <a href="https://api.slack.com/apps">https://api.slack.com/apps</a>, chọn <strong>Create an app →</strong> <strong>From Scratch (điền tên và chọn workspace)</strong></li>
</ul>



<figure class="wp-block-image size-full"><img decoding="async" width="736" height="816" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-20.17.47-1.png" alt="" class="wp-image-2772" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-20.17.47-1.png 736w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-20.17.47-1-271x300.png 271w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-20.17.47-1-380x421.png 380w" sizes="(max-width: 736px) 100vw, 736px" /></figure>



<ul class="wp-block-list">
<li>Chọn tab <strong>Incoming Webhooks</strong> bạn sẽ có: 
<ul class="wp-block-list">
<li><strong>Webhook URL</strong></li>



<li><strong>Channel</strong></li>
</ul>
</li>
</ul>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1015" height="668" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-20.19.11.png" alt="" class="wp-image-2773" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-20.19.11.png 1015w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-20.19.11-300x197.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-20.19.11-768x505.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-20.19.11-380x250.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-20.19.11-800x527.png 800w" sizes="auto, (max-width: 1015px) 100vw, 1015px" /></figure>



<h3 id="setup-rails" class="wp-block-heading"><strong>Setup Rails:</strong></h3>



<p>Đầu tiên, bạn tự thêm gem vào trong <strong>Gemfile</strong> và <strong>Bundle</strong> nhé.</p>



<h5 id="1-su-dung-slack-notifier" class="wp-block-heading">1. Sử dụng <code>slack-notifier</code></h5>



<ul class="wp-block-list">
<li><code>gem "slack-notifier"</code> <a href="https://github.com/slack-notifier/slack-notifier">https://github.com/slack-notifier/slack-notifier</a></li>



<li>Tạo 1 module <strong>SlackNotifier</strong> để tiện cho việc gọi khi cần.
<ul class="wp-block-list">
<li><strong>ENV[&#8216;SLACK_WEBHOOK_URL&#8217;], ENV[&#8216;SLACK_CHANNEL_SLACK&#8217;]</strong> bạn lấy ở bên trên.</li>



<li><strong>ENV[&#8216;SLACK_USERNAME_SLACK&#8217;]</strong> bạn đặt tự do.</li>
</ul>
</li>
</ul>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:17.3125px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Ruby</span><span role="button" tabindex="0" data-code="#config/initializers create slack_notifier.rb

module SlackNotifier
  CLIENT = Slack::Notifier.new(
    ENV['SLACK_WEBHOOK_URL'],
    channel: ENV['SLACK_CHANNEL_SLACK'],
    username: ENV['SLACK_USERNAME_SLACK']
  )
end

SlackNotifier::CLIENT.ping &quot;Hello Everybody!&quot;
SlackNotifier::CLIENT.ping &quot;TEST SLACK NOTIFICATION&quot;
" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #7B7F8B">#config/initializers create slack_notifier.rb</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">module</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">SlackNotifier</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #BF9EEE">CLIENT</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">Slack</span><span style="color: #F286C4">::</span><span style="color: #97E1F1; font-style: italic">Notifier</span><span style="color: #F6F6F4">.</span><span style="color: #F286C4">new</span><span style="color: #F6F6F4">(</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #BF9EEE">ENV</span><span style="color: #F6F6F4">[</span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">SLACK_WEBHOOK_URL</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">],</span></span>
<span class="line"><span style="color: #F6F6F4">    channel</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">ENV</span><span style="color: #F6F6F4">[</span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">SLACK_CHANNEL_SLACK</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">],</span></span>
<span class="line"><span style="color: #F6F6F4">    username</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">ENV</span><span style="color: #F6F6F4">[</span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">SLACK_USERNAME_SLACK</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">]</span></span>
<span class="line"><span style="color: #F6F6F4">  )</span></span>
<span class="line"><span style="color: #F286C4">end</span></span>
<span class="line"></span>
<span class="line"><span style="color: #97E1F1; font-style: italic">SlackNotifier</span><span style="color: #F286C4">::</span><span style="color: #97E1F1; font-style: italic">CLIENT</span><span style="color: #F6F6F4">.ping </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">Hello Everybody!</span><span style="color: #DEE492">&quot;</span></span>
<span class="line"><span style="color: #97E1F1; font-style: italic">SlackNotifier</span><span style="color: #F286C4">::</span><span style="color: #97E1F1; font-style: italic">CLIENT</span><span style="color: #F6F6F4">.ping </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">TEST SLACK NOTIFICATION</span><span style="color: #DEE492">&quot;</span></span>
<span class="line"></span></code></pre></div>



<ul class="wp-block-list">
<li>Kết quả</li>
</ul>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="576" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-20.34.40-1024x576.png" alt="" class="wp-image-2774" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-20.34.40-1024x576.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-20.34.40-300x169.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-20.34.40-768x432.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-20.34.40-1536x864.png 1536w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-20.34.40-2048x1152.png 2048w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-20.34.40-380x214.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-20.34.40-800x450.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-20.34.40-1160x653.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-20.34.40.png 2072w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<ul class="wp-block-list">
<li>Ngoài ra, bạn có thể custom nhiều hơn nữa,<strong> <em>xem thêm</em></strong> <strong><em>tại</em></strong> <a href="https://github.com/slack-notifier/slack-notifier">https://github.com/slack-notifier/slack-notifier</a></li>
</ul>



<h5 id="2-su-dung-exception-notification" class="wp-block-heading">2. Sử dụng exception-notification</h5>



<ul class="wp-block-list">
<li>Gem này sẽ tự động gửi exception về slack của bạn khi Rails App xảy exception. Nó giúp việc giám sát hệ thống, giúp bạn nhanh chóng kiểm tra, sửa chữa kịp thời.</li>



<li><code>gem exception_notification</code><a href=" https://github.com/smartinez87/exception_notification"> </a><a href="https://github.com/smartinez87/exception_notification">https://github.com/smartinez87/exception_notification</a></li>



<li><strong>Nếu ở production</strong>: <em>config/environments/production.rb</em></li>
</ul>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.65625px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Ruby</span><span role="button" tabindex="0" data-code="#config/environments/development.rb

Rails.application.config.middleware.use ExceptionNotification::Rack, slack: {
  webhook_url: ENV['SLACK_WEBHOOK_URL'],
  channel: ENV['SLACK_CHANNEL_NAME']
	}

" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #7B7F8B">#config/environments/development.rb</span></span>
<span class="line"></span>
<span class="line"><span style="color: #97E1F1; font-style: italic">Rails</span><span style="color: #F6F6F4">.application.config.middleware.use </span><span style="color: #97E1F1; font-style: italic">ExceptionNotification</span><span style="color: #F286C4">::</span><span style="color: #BF9EEE">Rack</span><span style="color: #F6F6F4">, slack</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  webhook_url</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">ENV</span><span style="color: #F6F6F4">[</span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">SLACK_WEBHOOK_URL</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">],</span></span>
<span class="line"><span style="color: #F6F6F4">  channel</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">ENV</span><span style="color: #F6F6F4">[</span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">SLACK_CHANNEL_NAME</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">]</span></span>
<span class="line"><span style="color: #F6F6F4">	}</span></span>
<span class="line"></span>
<span class="line"></span></code></pre></div>



<ul class="wp-block-list">
<li>Đặt ở nơi bạn muốn push notify nhé.</li>
</ul>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:17.3125px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Ruby</span><span role="button" tabindex="0" data-code="rescue_from StandardError do |e|
  ExceptionNotifier.notify_exception(e, 
		data: {
			# custom message ... 
			messages: e.messages
			date: Date.current
		}
	)
end
" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F6F6F4">rescue_from </span><span style="color: #BF9EEE">StandardError</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">do</span><span style="color: #F6F6F4"> |e|</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1; font-style: italic">ExceptionNotifier</span><span style="color: #F6F6F4">.notify_exception(e, </span></span>
<span class="line"><span style="color: #F6F6F4">		data</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">			</span><span style="color: #7B7F8B"># custom message ... </span></span>
<span class="line"><span style="color: #F6F6F4">			messages</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> e.messages</span></span>
<span class="line"><span style="color: #F6F6F4">			date</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">Date</span><span style="color: #F6F6F4">.current</span></span>
<span class="line"><span style="color: #F6F6F4">		}</span></span>
<span class="line"><span style="color: #F6F6F4">	)</span></span>
<span class="line"><span style="color: #F286C4">end</span></span>
<span class="line"></span></code></pre></div>



<ul class="wp-block-list">
<li>Kết quả</li>
</ul>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="732" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-22.55.23-1024x732.png" alt="" class="wp-image-2775" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-22.55.23-1024x732.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-22.55.23-300x215.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-22.55.23-768x549.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-22.55.23-1536x1098.png 1536w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-22.55.23-2048x1465.png 2048w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-22.55.23-380x272.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-22.55.23-800x572.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-22.55.23-1160x830.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-20-at-22.55.23.png 2078w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<ul class="wp-block-list">
<li>Ngoài ra, bạn có thể custom nhiều hơn nữa, <strong>x<em>em thêm tại</em></strong> <a href="https://github.com/smartinez87/exception_notification">https://github.com/smartinez87/exception_notification</a></li>
</ul>



<p>Hi vọng bài viết sẽ giúp ích được mọi người.</p>



<p>Cảm ơn mọi người.</p>



<p></p>
<p>The post <a href="https://blog.tomosia.com.vn/setup-slack-notifications-in-rails/">Setup slack notifications in Rails</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.tomosia.com.vn/setup-slack-notifications-in-rails/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>Building a GraphQL API in Rails</title>
		<link>https://blog.tomosia.com.vn/building-a-graphql-api-in-rails/</link>
					<comments>https://blog.tomosia.com.vn/building-a-graphql-api-in-rails/#comments</comments>
		
		<dc:creator><![CDATA[Hổ Nguyễn]]></dc:creator>
		<pubDate>Wed, 29 Nov 2023 02:55:14 +0000</pubDate>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[GraphQL]]></category>
		<category><![CDATA[Ruby On Rails]]></category>
		<guid isPermaLink="false">https://blog.tomosia.com.vn/?p=2050</guid>

					<description><![CDATA[<p>Trong thế giới phát triển web, API (Giao diện Lập trình Ứng dụng) đóng vai trò quan trọng&#8230;</p>
<p>The post <a href="https://blog.tomosia.com.vn/building-a-graphql-api-in-rails/">Building a GraphQL API in Rails</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Trong thế giới phát triển web, API (Giao diện Lập trình Ứng dụng) đóng vai trò quan trọng trong việc kích thích sự giao tiếp giữa các hệ thống phần mềm khác nhau. GraphQL, một ngôn ngữ truy vấn dành cho API, đã thu hút sự chú ý lớn với tính linh hoạt và hiệu suất cao trong việc truy xuất dữ liệu.</p>



<p>Trong bài đăng blog này, chúng ta sẽ khám phá quá trình xây dựng một GraphQL API trong Ruby on Rails, một framework mạnh mẽ và thân thiện với nhà phát triển.</p>



<h2 id="graphql-la-gi" class="wp-block-heading">GraphQL là gì?</h2>



<p>GraphQL là một ngôn ngữ truy vấn dành cho API và là một runtime để thực hiện những truy vấn đó đối với dữ liệu của bạn. Khác với các API REST truyền thống, nơi máy khách có kiểm soát hạn chế về dữ liệu mà nó nhận được, GraphQL cho phép máy khách yêu cầu chỉ những dữ liệu cần thiết. Điều này dẫn đến quá trình truy xuất dữ liệu hiệu quả và chính xác hơn.</p>



<h2 id="thiet-lap-du-an-rails" class="wp-block-heading">Thiết Lập Dự Án Rails</h2>



<p>Trước khi đào sâu vào GraphQL, hãy thiết lập một dự án Rails mới. Mở terminal và chạy các lệnh sau:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4296875px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Bash</span><span role="button" tabindex="0" data-code="rails new graphql_api 
cd graphql_api" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #62E884">rails</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">new</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">graphql_api</span><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #97E1F1">cd</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">graphql_api</span></span></code></pre></div>



<h2 id="them-dependencies" class="wp-block-heading">Thêm Dependencies</h2>



<p>Để tích hợp GraphQL vào dự án Rails của bạn, bạn sẽ cần thêm một số gems vào Gemfile. Mở Gemfile và bao gồm các dòng sau:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4296875px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Ruby</span><span role="button" tabindex="0" data-code="# Gemfile 

gem 'graphql' 
gem 'graphiql-rails', group: :development" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #7B7F8B"># Gemfile </span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">gem </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">graphql</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">gem </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">graphiql-rails</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">, group</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">:development</span></span></code></pre></div>



<p>Chạy <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-red-color"><code>bundle install</code> </mark>để cài đặt các gems này.</p>



<h2 id="tao-schema-graphql" class="wp-block-heading">Tạo Schema GraphQL</h2>



<p>Trong GraphQL, schema xác định các loại và các hoạt động có thể thực hiện trên dữ liệu của bạn. Hãy tạo một schema đơn giản cho ứng dụng blog. Chạy lệnh sau để tạo một schema GraphQL mới:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4296875px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Bash</span><span role="button" tabindex="0" data-code="rails generate graphql:install" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #62E884">rails</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">generate</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">graphql:install</span></span></code></pre></div>



<p>Lệnh này sẽ tạo một thư mục <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-red-color">graphql</mark></code> trong thư mục dự án của bạn, chứa một tệp schema cơ bản (<code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-red-color">app/graphql/types/query_type.rb</mark></code>). Tùy chỉnh tệp này để xác định schema GraphQL của bạn.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Ruby</span><span role="button" tabindex="0" data-code="# app/graphql/types/query_type.rb 

module Types 
  class QueryType &lt; Types::BaseObject 
    field :posts, [Types::PostType], null: false 
    
    def posts 
      Post.all
    end 
  end 
end" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #7B7F8B"># app/graphql/types/query_type.rb </span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">module</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">Types</span><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #F286C4">class</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">QueryType</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">&lt;</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">Types::BaseObject</span><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    field </span><span style="color: #BF9EEE">:posts</span><span style="color: #F6F6F4">, [</span><span style="color: #97E1F1; font-style: italic">Types</span><span style="color: #F286C4">::</span><span style="color: #BF9EEE">PostType</span><span style="color: #F6F6F4">], null</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">false</span><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">def</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">posts</span><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #97E1F1; font-style: italic">Post</span><span style="color: #F6F6F4">.all</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">end</span><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #F286C4">end</span><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F286C4">end</span></span></code></pre></div>



<h2 id="dinh-nghia-cac-loai" class="wp-block-heading">Định Nghĩa Các Loại</h2>



<p>Trong ví dụ này, chúng ta đã tạo một trường <code><strong>posts</strong></code> trả về một mảng các đối tượng <code><strong>Post</strong></code>. Bạn cũng cần xác định <code><strong>PostType</strong></code>.</p>



<ul class="wp-block-list">
<li>Đừng quên là hãy chạy lệnh <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-red-color">rails generate model Post title:string content:text</mark> và <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-red-color">rails db:migrate</mark> để tạo ra bảng <strong>Post</strong> trước</li>
</ul>



<p>Tạo một tệp mới <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-red-color">app/graphql/types/post_type.rb</mark></code>:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4296875px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Ruby</span><span role="button" tabindex="0" data-code="# app/graphql/types/post_type.rb 

module Types 
  class PostType &lt; Types::BaseObject 
    field :id, ID, null: false 
    field :title, String, null: false 
    field :content, String, null: false 
  end 
end" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #7B7F8B"># app/graphql/types/post_type.rb </span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">module</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">Types</span><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #F286C4">class</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">PostType</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">&lt;</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">Types::BaseObject</span><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    field </span><span style="color: #BF9EEE">:id</span><span style="color: #F6F6F4">, </span><span style="color: #BF9EEE">ID</span><span style="color: #F6F6F4">, null</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">false</span><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    field </span><span style="color: #BF9EEE">:title</span><span style="color: #F6F6F4">, </span><span style="color: #BF9EEE">String</span><span style="color: #F6F6F4">, null</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">false</span><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    field </span><span style="color: #BF9EEE">:content</span><span style="color: #F6F6F4">, </span><span style="color: #BF9EEE">String</span><span style="color: #F6F6F4">, null</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">false</span><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #F286C4">end</span><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F286C4">end</span></span></code></pre></div>



<p>Tệp này xác định cấu trúc của một loại <code><strong>Post</strong></code> với các trường <code><strong>id</strong></code>, <code><strong>title</strong></code>, và <code><strong>content</strong></code>.</p>



<h2 id="kiem-thu-voi-graphiql" class="wp-block-heading">Kiểm Thử với GraphiQL</h2>



<p>GraphiQL là một công cụ đồ họa tương tác trực tuyến dành cho GraphQL giúp đơn giản hóa quá trình kiểm thử các truy vấn GraphQL của bạn. Để kích hoạt GraphiQL, mở tệp <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-red-color">config/routes.rb</mark></code> và thêm các dòng sau:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4296875px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Ruby</span><span role="button" tabindex="0" data-code="# config/routes.rb 

if Rails.env.development? 
  mount GraphiQL::Rails::Engine, at: &quot;/graphiql&quot;, graphql_path: &quot;/graphql&quot; end 
  
post &quot;/graphql&quot;, to: &quot;graphql#execute&quot;" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #7B7F8B"># config/routes.rb </span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">if</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">Rails</span><span style="color: #F6F6F4">.env.development? </span></span>
<span class="line"><span style="color: #F6F6F4">  mount </span><span style="color: #97E1F1; font-style: italic">GraphiQL</span><span style="color: #F286C4">::</span><span style="color: #97E1F1; font-style: italic">Rails</span><span style="color: #F286C4">::</span><span style="color: #BF9EEE">Engine</span><span style="color: #F6F6F4">, at</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">/graphiql</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">, graphql_path</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">/graphql</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">end</span><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">  </span></span>
<span class="line"><span style="color: #F6F6F4">post </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">/graphql</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">, to</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">graphql#execute</span><span style="color: #DEE492">&quot;</span></span></code></pre></div>



<p>Bây giờ, khi bạn chạy máy chủ Rails của mình (<code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-red-color">rails server</mark></code>), bạn có thể truy cập <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-red-color">http://localhost:3000/graphiql</mark></code> để tương tác với GraphQL API của bạn.</p>



<h2 id="thuc-hien-cac-truy-van" class="wp-block-heading">Thực Hiện Các Truy Vấn</h2>



<p>Bây giờ, bạn có thể kiểm thử các truy vấn GraphQL của mình trong GraphiQL. Ví dụ:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4296875px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">GraphQL</span><span role="button" tabindex="0" data-code="query {
  posts {
    id
    title
    content
  }
}" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">query</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #E7EE98">posts</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #E7EE98">id</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #E7EE98">title</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #E7EE98">content</span></span>
<span class="line"><span style="color: #F6F6F4">  }</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span></code></pre></div>



<p>Truy vấn này sẽ truy xuất tất cả các bài viết cùng với các trường <strong><code>id</code>, <code>title</code></strong>, và <code><strong>content</strong></code>.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="582" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screenshot-2023-11-28-at-10.17.45-AM-1024x582.png" alt="" class="wp-image-2056" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screenshot-2023-11-28-at-10.17.45-AM-1024x582.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screenshot-2023-11-28-at-10.17.45-AM-300x170.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screenshot-2023-11-28-at-10.17.45-AM-768x436.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screenshot-2023-11-28-at-10.17.45-AM-1536x873.png 1536w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screenshot-2023-11-28-at-10.17.45-AM-2048x1163.png 2048w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screenshot-2023-11-28-at-10.17.45-AM-380x216.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screenshot-2023-11-28-at-10.17.45-AM-800x454.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screenshot-2023-11-28-at-10.17.45-AM-1160x659.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screenshot-2023-11-28-at-10.17.45-AM.png 2880w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Chúc mừng! Bạn đã xây dựng thành công một GraphQL API trong Ruby on Rails. <br>Happy coding!</p>
<p>The post <a href="https://blog.tomosia.com.vn/building-a-graphql-api-in-rails/">Building a GraphQL API in Rails</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.tomosia.com.vn/building-a-graphql-api-in-rails/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
			</item>
		<item>
		<title>[ROR] Hướng dẫn setup CircleCI &#038; Code Quality</title>
		<link>https://blog.tomosia.com.vn/ror-huong-dan-setup-circleci-code-quality/</link>
					<comments>https://blog.tomosia.com.vn/ror-huong-dan-setup-circleci-code-quality/#comments</comments>
		
		<dc:creator><![CDATA[Thuan Nguyen Van]]></dc:creator>
		<pubDate>Wed, 22 Nov 2023 01:28:06 +0000</pubDate>
				<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[CI/CD]]></category>
		<category><![CDATA[Ruby On Rails]]></category>
		<category><![CDATA[Circle CI]]></category>
		<guid isPermaLink="false">https://blog.tomosia.com.vn/?p=1808</guid>

					<description><![CDATA[<p>Step 1: Access https://circleci.com/ and authorize a Github, Gitlab or Bitbucket account. I will use a Github account.&#8230;</p>
<p>The post <a href="https://blog.tomosia.com.vn/ror-huong-dan-setup-circleci-code-quality/">[ROR] Hướng dẫn setup CircleCI &#038; Code Quality</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p><strong>Step 1:</strong> Access <a href="https://circleci.com/">https://circleci.com/</a> and authorize a Github, Gitlab or Bitbucket account. I will use a Github account.</p>



<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/4-a7bO8VFdZjsOip_gK60WMFnOZJ0dD1PwI8ykJHCpPzJs-jjSvZekKGaQc7yth9dUIbdztuP4NDEC1F-xZMe7RDDys9RCbHf9EVDAIUCbvV2f9wvw-ZeUZH29uU_I72eS59O0zAyeOl88ueOYbhTw" alt=""/></figure>



<p><strong>Step 2</strong>: Click <strong>Go to Application </strong>in Home page -&gt; Projects</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="671" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.46.25-1024x671.png" alt="" class="wp-image-1828" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.46.25-1024x671.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.46.25-300x197.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.46.25-768x503.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.46.25-1536x1007.png 1536w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.46.25-2048x1342.png 2048w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.46.25-380x249.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.46.25-800x524.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.46.25-1160x760.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.46.25.png 2206w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p><strong>Step 3</strong>: Click to Setup Project button in the right Repo you want to setup</p>



<p><strong>Step 4</strong>: Select first Radio Button -&gt; Set Up Project</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="960" height="820" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.46.54.png" alt="" class="wp-image-1830" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.46.54.png 960w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.46.54-300x256.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.46.54-768x656.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.46.54-380x325.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.46.54-800x683.png 800w" sizes="auto, (max-width: 960px) 100vw, 960px" /></figure>



<p>After setup, click <strong>Dashboard </strong>and display as below</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="555" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.49.23-1024x555.png" alt="" class="wp-image-1831" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.49.23-1024x555.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.49.23-300x163.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.49.23-768x417.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.49.23-1536x833.png 1536w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.49.23-2048x1111.png 2048w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.49.23-380x206.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.49.23-800x434.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.49.23-1160x629.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-11-15-at-08.49.23.png 2360w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p><strong>Step 5</strong>: Click <strong>Project Setting -&gt; SSH Key </strong>and check if the ssh key has been linked or not.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="602" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-10.37.42-2-1024x602.png" alt="" class="wp-image-1926" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-10.37.42-2-1024x602.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-10.37.42-2-300x176.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-10.37.42-2-768x452.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-10.37.42-2-1536x903.png 1536w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-10.37.42-2-380x223.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-10.37.42-2-800x471.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-10.37.42-2-1160x682.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-10.37.42-2.png 1600w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Step 6: <strong>If you using Git Submodule,</strong> please create a Additional SSH Keys</p>



<ol class="wp-block-list">
<li>Open terminal and run <strong><code>ssh-keygen -t ed25519 -C "Circle CI".</code></strong></li>



<li>Click Add SSH Key and enter</li>
</ol>



<ul class="wp-block-list">
<li>Hostname: <strong>github.com</strong></li>



<li>Private Key: cat <strong>minh_id_ed25519</strong>, copy and paste</li>
</ul>



<ol class="wp-block-list" start="3">
<li>Back to Github, select Repository <strong>Shared submodule</strong> -&gt; <strong>Settings</strong> -&gt; <strong>Deploy Keys</strong> -&gt; <strong>Add deploy key</strong></li>



<li>Enter Title and Key -&gt; <strong>Add Key</strong></li>
</ol>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="524" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-10.38.40-3-1024x524.png" alt="" class="wp-image-1927" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-10.38.40-3-1024x524.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-10.38.40-3-300x154.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-10.38.40-3-768x393.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-10.38.40-3-1536x786.png 1536w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-10.38.40-3-380x195.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-10.38.40-3-800x410.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-10.38.40-3-1160x594.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-10.38.40-3.png 1600w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/DMqD1X_4hArkrqNjTitIIFNRe2HXnxxUpBu37aJgAH9XYYzgoDI2aE7GX8VLqt8cmKZiCl1EV0Nq_p7A7eOGg0ISwUcWUK-LdAqZdLg0heEL8GCH1qzpQI0lAHQxrtRcWJgnnSufCW9wVii8a7HUZQ" alt=""/></figure>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="810" height="511" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-10.48.56.png" alt="" class="wp-image-1928" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-10.48.56.png 810w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-10.48.56-300x189.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-10.48.56-768x485.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-10.48.56-380x240.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-10.48.56-800x505.png 800w" sizes="auto, (max-width: 810px) 100vw, 810px" /></figure>



<p><strong>Step 7</strong>: Back to project setup config CircleCI and Danger</p>



<ol class="wp-block-list">
<li>Add to Gemfile</li>
</ol>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Ruby</span><span role="button" tabindex="0" data-code="gem 'brakeman', require: false
gem 'danger', '9.2.0'
# A Danger plugin to lint Ruby files through danger-brakeman_scanner.&lt;/em&gt;
gem 'danger-brakeman_scanner', '0.1.1'
# A Danger plugin to lint Ruby files through rails_best_practices.&lt;/em&gt;
gem 'danger-rails_best_practices', '0.1.3'
# A Danger plugin to lint Ruby files through Reek.&lt;/em&gt;
gem 'danger-reek', '0.3.0'
# A Danger plugin for running Ruby files through Rubocop.&lt;/em&gt;
gem 'danger-rubocop', '0.10.0'
# A Danger plugin to report code coverage generated by SimpleCov in JSON format.&lt;/em&gt;
gem 'danger-simplecov_json', '0.3.0'" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F6F6F4">gem </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">brakeman</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">, require</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">false</span></span>
<span class="line"><span style="color: #F6F6F4">gem </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">danger</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">, </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">9.2.0</span><span style="color: #DEE492">&#39;</span></span>
<span class="line"><span style="color: #7B7F8B"># A Danger plugin to lint Ruby files through danger-brakeman_scanner.&lt;/em&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">gem </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">danger-brakeman_scanner</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">, </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">0.1.1</span><span style="color: #DEE492">&#39;</span></span>
<span class="line"><span style="color: #7B7F8B"># A Danger plugin to lint Ruby files through rails_best_practices.&lt;/em&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">gem </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">danger-rails_best_practices</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">, </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">0.1.3</span><span style="color: #DEE492">&#39;</span></span>
<span class="line"><span style="color: #7B7F8B"># A Danger plugin to lint Ruby files through Reek.&lt;/em&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">gem </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">danger-reek</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">, </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">0.3.0</span><span style="color: #DEE492">&#39;</span></span>
<span class="line"><span style="color: #7B7F8B"># A Danger plugin for running Ruby files through Rubocop.&lt;/em&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">gem </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">danger-rubocop</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">, </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">0.10.0</span><span style="color: #DEE492">&#39;</span></span>
<span class="line"><span style="color: #7B7F8B"># A Danger plugin to report code coverage generated by SimpleCov in JSON format.&lt;/em&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">gem </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">danger-simplecov_json</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">, </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">0.3.0</span><span style="color: #DEE492">&#39;</span></span></code></pre></div>



<ol class="wp-block-list" start="2">
<li>Create file in <strong>.circleci/config.yml</strong> and paste code</li>
</ol>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:25.296875px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Ruby</span><span role="button" tabindex="0" data-code="# Best practises:
#   [https://www.netguru.com/blog/top-10-best-practises-to-benefit-more-form-circleci]
#   [https://circleci.com/blog/six-optimization-tips-for-your-config/]
references:
  working_directory: &amp;working_directory ~/quinblog
  images:
    base_image: &amp;base_image
      image: cimg/ruby:3.2.1
      environment:
        TZ: /usr/share/zoneinfo/Asia/Tokyo
        BUNDLE_JOBS: 4
        BUNDLE_RETRY: 3
        BUNDLE_PATH: vendor/bundle
        GEM_PATH: vendor/bundle
        RAILS_ENV: test
    db_image: &amp;db_image
      image: cimg/postgres:14.4
      environment:
        POSTGRES_USER: postgres
        POSTGRES_DB: quinblog_test
        POSTGRES_PASSWORD: postgres
    redis_image: &amp;redis_image
      image: cimg/redis:5.0
    mongodb_image: &amp;mongodb_image
      image: circleci/mongo:3.6
  commands:
    move_database_yml: &amp;move_database_yml
      name: Move database_yml
      command: mv config/database.ci.yml config/database.yml
    move_mongoid_yml: &amp;move_mongoid_yml
      name: Move mongoid_yml
      command: mv config/mongoid.ci.yml config/mongoid.yml
    sync_git_submodule: &amp;sync_git_submodule
      name: Sync git submodule
      command: |
        git submodule sync --recursive --quiet
        git submodule update --init --checkout --recursive --quiet

# Use the latest 2.1 version of CircleCI pipeline process engine.
# See: https://circleci.com/docs/2.0/configuration-reference
version: 2.1

# Orbs are reusable packages of CircleCI configuration that you may share across projects, enabling you to create encapsulated, parameterized commands, jobs, and executors that can be used across multiple projects.
# See: https://circleci.com/docs/2.0/orb-intro/
orbs:
  ruby: circleci/ruby@1.8.0

# Define a job to be invoked later in a workflow.
# See: https://circleci.com/docs/2.0/configuration-reference/#jobs
jobs:
  build:
    working_directory: *working_directory
    resource_class: small
    parallelism: 1
    docker:
      - *base_image
    steps:
      - add_ssh_keys:
          fingerprints:
            - '7c:72:77:4f:79:12:cb:af:c9:84:7b:d1:ab:24:69:41'
      - checkout

      - run: *move_database_yml
      - run: *move_mongoid_yml
      - run: *sync_git_submodule
      - run:
          name: Disabled auto completion
          command: echo 'IRB.conf[:USE_AUTOCOMPLETE] = false' &gt;&gt; ~/.irbrc

      # Restoring and saving cache
      - ruby/install-deps

      - persist_to_workspace:
          root: *working_directory
          paths:
            - ./*

  test:
    working_directory: *working_directory
    resource_class: small
    parallelism: 2
    docker:
      - *base_image
      - *db_image
      - *mongodb_image
      - *redis_image
    steps:
      - attach_workspace:
          at: *working_directory

      - run:
          name: Wait for Postgres DB
          command: dockerize -wait tcp://localhost:5432 -timeout 1m

      - run:
          name: Wait for Mongo DB
          command: dockerize -wait tcp://localhost:27017 -timeout 1m

      - run:
          name: Wait for Redis DB
          command: dockerize -wait tcp://localhost:6379 -timeout 1m

      - run:
          name: Migration DB
          command: |
            bundle exec rails db:schema:load:primary --trace
            bundle exec rails db:create:universal
            bundle exec rails db:schema:load:universal --trace

      - run:
          name: Run rspec
          command: |
            TESTFILES=$(circleci tests glob &quot;spec/**/*_spec.rb&quot; | circleci tests split --split-by=timings --timings-type=classname)
            echo ${TESTFILES}
            bundle exec rspec --profile 10 \
                              --format progress \
                              --format RspecJunitFormatter --out /tmp/test-results/rspec/rspec.xml \
                              ${TESTFILES}

      # Collect test data
      # See: https://circleci.com/docs/collect-test-data
      # See: https://circleci.com/blog/how-to-output-junit-tests-through-circleci-2-0-for-expanded-insights/
      - store_test_results:
          path: /tmp/test-results/rspec/

      - run:
          name: Run danger
          command: bundle exec danger --danger_id=test

  lint:
    working_directory: *working_directory
    resource_class: small
    parallelism: 1
    docker:
      - *base_image
    steps:
      - attach_workspace:
          at: *working_directory

      - run:
          name: Run danger
          command: bundle exec danger --danger_id=lint

# Invoke jobs via workflows
# See: https://circleci.com/docs/2.0/configuration-reference/#workflows
workflows:
  build_and_test:
    jobs:
      - build
      - test:
          context:
            - ctx_renew_api_company
          requires:
            - build
      - lint:
          context:
            - ctx_renew_api_company
          requires:
            - build
" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #7B7F8B"># Best practises:</span></span>
<span class="line"><span style="color: #7B7F8B">#   [https://www.netguru.com/blog/top-10-best-practises-to-benefit-more-form-circleci]</span></span>
<span class="line"><span style="color: #7B7F8B">#   [https://circleci.com/blog/six-optimization-tips-for-your-config/]</span></span>
<span class="line"><span style="color: #F6F6F4">references</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">  working_directory</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">&amp;</span><span style="color: #F6F6F4">working_directory </span><span style="color: #F286C4">~</span><span style="color: #E7EE98">/quinblog</span></span>
<span class="line"><span style="color: #E7EE98">  images:</span></span>
<span class="line"><span style="color: #E7EE98">    base_image: &amp;base_image</span></span>
<span class="line"><span style="color: #E7EE98">      image: cimg/</span><span style="color: #F6F6F4">ruby</span><span style="color: #F286C4">:</span><span style="color: #BF9EEE">3.2</span><span style="color: #F6F6F4">.</span><span style="color: #BF9EEE">1</span></span>
<span class="line"><span style="color: #F6F6F4">      environment</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">        TZ</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">/usr/s</span><span style="color: #F6F6F4">hare</span><span style="color: #F286C4">/</span><span style="color: #F6F6F4">zoneinfo</span><span style="color: #F286C4">/</span><span style="color: #BF9EEE">Asia</span><span style="color: #F286C4">/</span><span style="color: #BF9EEE">Tokyo</span></span>
<span class="line"><span style="color: #F6F6F4">        BUNDLE_JOBS</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">4</span></span>
<span class="line"><span style="color: #F6F6F4">        BUNDLE_RETRY</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">3</span></span>
<span class="line"><span style="color: #F6F6F4">        BUNDLE_PATH</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> vendor</span><span style="color: #F286C4">/</span><span style="color: #F6F6F4">bundle</span></span>
<span class="line"><span style="color: #F6F6F4">        GEM_PATH</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> vendor</span><span style="color: #F286C4">/</span><span style="color: #F6F6F4">bundle</span></span>
<span class="line"><span style="color: #F6F6F4">        RAILS_ENV</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">test</span></span>
<span class="line"><span style="color: #F6F6F4">    db_image</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">&amp;</span><span style="color: #F6F6F4">db_image</span></span>
<span class="line"><span style="color: #F6F6F4">      image</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> cimg</span><span style="color: #F286C4">/</span><span style="color: #F6F6F4">postgres</span><span style="color: #F286C4">:</span><span style="color: #BF9EEE">14.4</span></span>
<span class="line"><span style="color: #F6F6F4">      environment</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">        POSTGRES_USER</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> postgres</span></span>
<span class="line"><span style="color: #F6F6F4">        POSTGRES_DB</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> quinblog_test</span></span>
<span class="line"><span style="color: #F6F6F4">        POSTGRES_PASSWORD</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> postgres</span></span>
<span class="line"><span style="color: #F6F6F4">    redis_image</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">&amp;</span><span style="color: #F6F6F4">redis_image</span></span>
<span class="line"><span style="color: #F6F6F4">      image</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> cimg</span><span style="color: #F286C4">/</span><span style="color: #F6F6F4">redis</span><span style="color: #F286C4">:</span><span style="color: #BF9EEE">5.0</span></span>
<span class="line"><span style="color: #F6F6F4">    mongodb_image</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">&amp;</span><span style="color: #F6F6F4">mongodb_image</span></span>
<span class="line"><span style="color: #F6F6F4">      image</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> circleci</span><span style="color: #F286C4">/</span><span style="color: #F6F6F4">mongo</span><span style="color: #F286C4">:</span><span style="color: #BF9EEE">3.6</span></span>
<span class="line"><span style="color: #F6F6F4">  commands</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">    move_database_yml</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">&amp;</span><span style="color: #F6F6F4">move_database_yml</span></span>
<span class="line"><span style="color: #F6F6F4">      name</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">Move</span><span style="color: #F6F6F4"> database_yml</span></span>
<span class="line"><span style="color: #F6F6F4">      command</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> mv config</span><span style="color: #F286C4">/</span><span style="color: #F6F6F4">database.ci.yml config</span><span style="color: #F286C4">/</span><span style="color: #F6F6F4">database.yml</span></span>
<span class="line"><span style="color: #F6F6F4">    move_mongoid_yml</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">&amp;</span><span style="color: #F6F6F4">move_mongoid_yml</span></span>
<span class="line"><span style="color: #F6F6F4">      name</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">Move</span><span style="color: #F6F6F4"> mongoid_yml</span></span>
<span class="line"><span style="color: #F6F6F4">      command</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> mv config</span><span style="color: #F286C4">/</span><span style="color: #F6F6F4">mongoid.ci.yml config</span><span style="color: #F286C4">/</span><span style="color: #F6F6F4">mongoid.yml</span></span>
<span class="line"><span style="color: #F6F6F4">    sync_git_submodule</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">&amp;</span><span style="color: #F6F6F4">sync_git_submodule</span></span>
<span class="line"><span style="color: #F6F6F4">      name</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">Sync</span><span style="color: #F6F6F4"> git submodule</span></span>
<span class="line"><span style="color: #F6F6F4">      command</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">|</span></span>
<span class="line"><span style="color: #F6F6F4">        git submodule sync </span><span style="color: #F286C4">--</span><span style="color: #F6F6F4">recursive </span><span style="color: #F286C4">--</span><span style="color: #F6F6F4">quiet</span></span>
<span class="line"><span style="color: #F6F6F4">        git submodule update </span><span style="color: #F286C4">--</span><span style="color: #F6F6F4">init </span><span style="color: #F286C4">--</span><span style="color: #F6F6F4">checkout </span><span style="color: #F286C4">--</span><span style="color: #F6F6F4">recursive </span><span style="color: #F286C4">--</span><span style="color: #F6F6F4">quiet</span></span>
<span class="line"></span>
<span class="line"><span style="color: #7B7F8B"># Use the latest 2.1 version of CircleCI pipeline process engine.</span></span>
<span class="line"><span style="color: #7B7F8B"># See: https://circleci.com/docs/2.0/configuration-reference</span></span>
<span class="line"><span style="color: #F6F6F4">version</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">2.1</span></span>
<span class="line"></span>
<span class="line"><span style="color: #7B7F8B"># Orbs are reusable packages of CircleCI configuration that you may share across projects, enabling you to create encapsulated, parameterized commands, jobs, and executors that can be used across multiple projects.</span></span>
<span class="line"><span style="color: #7B7F8B"># See: https://circleci.com/docs/2.0/orb-intro/</span></span>
<span class="line"><span style="color: #F6F6F4">orbs</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">  ruby</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> circleci</span><span style="color: #F286C4">/</span><span style="color: #F6F6F4">ruby@</span><span style="color: #BF9EEE">1.8</span><span style="color: #F6F6F4">.</span><span style="color: #BF9EEE">0</span></span>
<span class="line"></span>
<span class="line"><span style="color: #7B7F8B"># Define a job to be invoked later in a workflow.</span></span>
<span class="line"><span style="color: #7B7F8B"># See: https://circleci.com/docs/2.0/configuration-reference/#jobs</span></span>
<span class="line"><span style="color: #F6F6F4">jobs</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">  build</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">    working_directory</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">*</span><span style="color: #F6F6F4">working_directory</span></span>
<span class="line"><span style="color: #F6F6F4">    resource_class</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> small</span></span>
<span class="line"><span style="color: #F6F6F4">    parallelism</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">1</span></span>
<span class="line"><span style="color: #F6F6F4">    docker</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">*</span><span style="color: #F6F6F4">base_image</span></span>
<span class="line"><span style="color: #F6F6F4">    steps</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> add_ssh_keys</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">          fingerprints</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">            </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">7c:72:77:4f:79:12:cb:af:c9:84:7b:d1:ab:24:69:41</span><span style="color: #DEE492">&#39;</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> checkout</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> run</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">*</span><span style="color: #F6F6F4">move_database_yml</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> run</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">*</span><span style="color: #F6F6F4">move_mongoid_yml</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> run</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">*</span><span style="color: #F6F6F4">sync_git_submodule</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> run</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">          name</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">Disabled</span><span style="color: #F6F6F4"> auto completion</span></span>
<span class="line"><span style="color: #F6F6F4">          command</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> echo </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">IRB.conf[:USE_AUTOCOMPLETE] = false</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">&gt;&gt;</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">~</span><span style="color: #E7EE98">/.irbrc</span></span>
<span class="line"></span>
<span class="line"><span style="color: #E7EE98">      </span><span style="color: #7B7F8B"># Restoring and saving cache</span></span>
<span class="line"><span style="color: #E7EE98">      - ruby/ins</span><span style="color: #F6F6F4">tall</span><span style="color: #F286C4">-</span><span style="color: #F6F6F4">deps</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> persist_to_workspace</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">          root</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">*</span><span style="color: #F6F6F4">working_directory</span></span>
<span class="line"><span style="color: #F6F6F4">          paths</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">            </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> .</span><span style="color: #F286C4">/*</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">  test</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">    working_directory</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">*</span><span style="color: #F6F6F4">working_directory</span></span>
<span class="line"><span style="color: #F6F6F4">    resource_class</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> small</span></span>
<span class="line"><span style="color: #F6F6F4">    parallelism</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">2</span></span>
<span class="line"><span style="color: #F6F6F4">    docker</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">*</span><span style="color: #F6F6F4">base_image</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">*</span><span style="color: #F6F6F4">db_image</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">*</span><span style="color: #F6F6F4">mongodb_image</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">*</span><span style="color: #F6F6F4">redis_image</span></span>
<span class="line"><span style="color: #F6F6F4">    steps</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> attach_workspace</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">          at</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">*</span><span style="color: #F6F6F4">working_directory</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> run</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">          name</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">Wait</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">for</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">Postgres</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">DB</span></span>
<span class="line"><span style="color: #F6F6F4">          command</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> dockerize </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4">wait tcp</span><span style="color: #F286C4">:</span><span style="color: #E7EE98">//</span><span style="color: #F6F6F4">localhost</span><span style="color: #F286C4">:</span><span style="color: #BF9EEE">5432</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4">timeout 1m</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> run</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">          name</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">Wait</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">for</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">Mongo</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">DB</span></span>
<span class="line"><span style="color: #F6F6F4">          command</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> dockerize </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4">wait tcp</span><span style="color: #F286C4">:</span><span style="color: #E7EE98">//</span><span style="color: #F6F6F4">localhost</span><span style="color: #F286C4">:</span><span style="color: #BF9EEE">27017</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4">timeout 1m</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> run</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">          name</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">Wait</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">for</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">Redis</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">DB</span></span>
<span class="line"><span style="color: #F6F6F4">          command</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> dockerize </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4">wait tcp</span><span style="color: #F286C4">:</span><span style="color: #E7EE98">//</span><span style="color: #F6F6F4">localhost</span><span style="color: #F286C4">:</span><span style="color: #BF9EEE">6379</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4">timeout 1m</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> run</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">          name</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">Migration</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">DB</span></span>
<span class="line"><span style="color: #F6F6F4">          command</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">|</span></span>
<span class="line"><span style="color: #F6F6F4">            bundle </span><span style="color: #97E1F1">exec</span><span style="color: #F6F6F4"> rails db</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4">schema</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4">load</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4">primary </span><span style="color: #F286C4">--</span><span style="color: #F6F6F4">trace</span></span>
<span class="line"><span style="color: #F6F6F4">            bundle </span><span style="color: #97E1F1">exec</span><span style="color: #F6F6F4"> rails db</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4">create</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4">universal</span></span>
<span class="line"><span style="color: #F6F6F4">            bundle </span><span style="color: #97E1F1">exec</span><span style="color: #F6F6F4"> rails db</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4">schema</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4">load</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4">universal </span><span style="color: #F286C4">--</span><span style="color: #F6F6F4">trace</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> run</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">          name</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">Run</span><span style="color: #F6F6F4"> rspec</span></span>
<span class="line"><span style="color: #F6F6F4">          command</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">|</span></span>
<span class="line"><span style="color: #F6F6F4">            </span><span style="color: #BF9EEE">TESTFILES</span><span style="color: #F286C4">=</span><span style="color: #F6F6F4">$(circleci tests glob </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">spec/**/*_spec.rb</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">|</span><span style="color: #F6F6F4"> circleci tests split </span><span style="color: #F286C4">--</span><span style="color: #F6F6F4">split</span><span style="color: #F286C4">-</span><span style="color: #F6F6F4">by</span><span style="color: #F286C4">=</span><span style="color: #F6F6F4">timings </span><span style="color: #F286C4">--</span><span style="color: #F6F6F4">timings</span><span style="color: #F286C4">-</span><span style="color: #F6F6F4">type</span><span style="color: #F286C4">=</span><span style="color: #F6F6F4">classname)</span></span>
<span class="line"><span style="color: #F6F6F4">            echo ${</span><span style="color: #BF9EEE">TESTFILES</span><span style="color: #F6F6F4">}</span></span>
<span class="line"><span style="color: #F6F6F4">            bundle </span><span style="color: #97E1F1">exec</span><span style="color: #F6F6F4"> rspec </span><span style="color: #F286C4">--</span><span style="color: #F6F6F4">profile </span><span style="color: #BF9EEE">10</span><span style="color: #F6F6F4"> \</span></span>
<span class="line"><span style="color: #F6F6F4">                              </span><span style="color: #F286C4">--</span><span style="color: #97E1F1">format</span><span style="color: #F6F6F4"> progress \</span></span>
<span class="line"><span style="color: #F6F6F4">                              </span><span style="color: #F286C4">--</span><span style="color: #97E1F1">format</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">RspecJunitFormatter</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">--</span><span style="color: #F6F6F4">out </span><span style="color: #F286C4">/</span><span style="color: #F6F6F4">tmp</span><span style="color: #F286C4">/</span><span style="color: #97E1F1">test</span><span style="color: #F286C4">-</span><span style="color: #F6F6F4">results</span><span style="color: #F286C4">/</span><span style="color: #F6F6F4">rspec</span><span style="color: #F286C4">/</span><span style="color: #F6F6F4">rspec.xml \</span></span>
<span class="line"><span style="color: #F6F6F4">                              ${</span><span style="color: #BF9EEE">TESTFILES</span><span style="color: #F6F6F4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #7B7F8B"># Collect test data</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #7B7F8B"># See: https://circleci.com/docs/collect-test-data</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #7B7F8B"># See: https://circleci.com/blog/how-to-output-junit-tests-through-circleci-2-0-for-expanded-insights/</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> store_test_results</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">          path</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">/tmp/</span><span style="color: #97E1F1">test</span><span style="color: #F286C4">-</span><span style="color: #F6F6F4">results</span><span style="color: #F286C4">/</span><span style="color: #F6F6F4">rspec</span><span style="color: #F286C4">/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> run</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">          name</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">Run</span><span style="color: #F6F6F4"> danger</span></span>
<span class="line"><span style="color: #F6F6F4">          command</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> bundle </span><span style="color: #97E1F1">exec</span><span style="color: #F6F6F4"> danger </span><span style="color: #F286C4">--</span><span style="color: #F6F6F4">danger_id</span><span style="color: #F286C4">=</span><span style="color: #97E1F1">test</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">  lint</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">    working_directory</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">*</span><span style="color: #F6F6F4">working_directory</span></span>
<span class="line"><span style="color: #F6F6F4">    resource_class</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> small</span></span>
<span class="line"><span style="color: #F6F6F4">    parallelism</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">1</span></span>
<span class="line"><span style="color: #F6F6F4">    docker</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">*</span><span style="color: #F6F6F4">base_image</span></span>
<span class="line"><span style="color: #F6F6F4">    steps</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> attach_workspace</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">          at</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">*</span><span style="color: #F6F6F4">working_directory</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> run</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">          name</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">Run</span><span style="color: #F6F6F4"> danger</span></span>
<span class="line"><span style="color: #F6F6F4">          command</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> bundle </span><span style="color: #97E1F1">exec</span><span style="color: #F6F6F4"> danger </span><span style="color: #F286C4">--</span><span style="color: #F6F6F4">danger_id</span><span style="color: #F286C4">=</span><span style="color: #F6F6F4">lint</span></span>
<span class="line"></span>
<span class="line"><span style="color: #7B7F8B"># Invoke jobs via workflows</span></span>
<span class="line"><span style="color: #7B7F8B"># See: https://circleci.com/docs/2.0/configuration-reference/#workflows</span></span>
<span class="line"><span style="color: #F6F6F4">workflows</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">  build_and_test</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">    jobs</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> build</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> test</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">          context</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">            </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> ctx_renew_api_company</span></span>
<span class="line"><span style="color: #F6F6F4">          requires</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">            </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> build</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> lint</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">          context</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">            </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> ctx_renew_api_company</span></span>
<span class="line"><span style="color: #F6F6F4">          requires</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">            </span><span style="color: #F286C4">-</span><span style="color: #F6F6F4"> build</span></span>
<span class="line"></span></code></pre></div>



<p><strong>Step 8</strong>: Config Danger. Create <strong>Dangerfile</strong> and paste code below:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Ruby</span><span role="button" tabindex="0" data-code="# frozen_string_literal: true

case ENV.fetch('CIRCLE_JOB', nil)

when 'lint'

  ### for Rubocop ###

  rubocop.lint(force_exclusion: true, inline_comment: true)

  ### for rails_best_practices ###

  # rails_best_practices.lint

  ### for Reek ###

  # reek.lint

  ### for brakeman ###

  brakeman.run('.')

  # Ensure there is a summary for a pr

  failure('Please provide a summary in the Pull Request description') if     github.pr_body.include?('___WRITE_HERE___')

  # Ensure that all prs have an assignee

  failure('This PR does not have any assignees yet.') unless github.pr_json['assignee']

  # Warn really big diffs

  warn('We cannot handle the scale of this PR') if git.lines_of_code &gt; 300

  # Note when a pr cannot be manually merged, which goes away when you can

  warn('This PR cannot be merged yet.', sticky: false) unless github.pr_json['mergeable']

 when 'test'

  ### for SimpleCov ###

  coverage_file = 'coverage/coverage.json'

  simplecov.report(coverage_file, sticky: false)

  simplecov.individual_report(coverage_file, Dir.pwd)

end" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #7B7F8B"># frozen_string_literal: true</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">case</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">ENV</span><span style="color: #F6F6F4">.fetch(</span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">CIRCLE_JOB</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">, </span><span style="color: #BF9EEE">nil</span><span style="color: #F6F6F4">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">when</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">lint</span><span style="color: #DEE492">&#39;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #7B7F8B">### for Rubocop ###</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">  rubocop.lint(force_exclusion</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">true</span><span style="color: #F6F6F4">, inline_comment</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">true</span><span style="color: #F6F6F4">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #7B7F8B">### for rails_best_practices ###</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #7B7F8B"># rails_best_practices.lint</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #7B7F8B">### for Reek ###</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #7B7F8B"># reek.lint</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #7B7F8B">### for brakeman ###</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">  brakeman.run(</span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">.</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #7B7F8B"># Ensure there is a summary for a pr</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">  failure(</span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">Please provide a summary in the Pull Request description</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">if</span><span style="color: #F6F6F4">     github.pr_body.include?(</span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">___WRITE_HERE___</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #7B7F8B"># Ensure that all prs have an assignee</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">  failure(</span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">This PR does not have any assignees yet.</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">unless</span><span style="color: #F6F6F4"> github.pr_json[</span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">assignee</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">]</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #7B7F8B"># Warn really big diffs</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">warn</span><span style="color: #F6F6F4">(</span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">We cannot handle the scale of this PR</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">if</span><span style="color: #F6F6F4"> git.lines_of_code </span><span style="color: #F286C4">&gt;</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">300</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #7B7F8B"># Note when a pr cannot be manually merged, which goes away when you can</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">warn</span><span style="color: #F6F6F4">(</span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">This PR cannot be merged yet.</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">, sticky</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">false</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">unless</span><span style="color: #F6F6F4"> github.pr_json[</span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">mergeable</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">]</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4"> </span><span style="color: #F286C4">when</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">test</span><span style="color: #DEE492">&#39;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #7B7F8B">### for SimpleCov ###</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">  coverage_file </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">coverage/coverage.json</span><span style="color: #DEE492">&#39;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">  simplecov.report(coverage_file, sticky</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">false</span><span style="color: #F6F6F4">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">  simplecov.individual_report(coverage_file, </span><span style="color: #97E1F1; font-style: italic">Dir</span><span style="color: #F6F6F4">.pwd)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">end</span></span></code></pre></div>



<p><strong>Step 9</strong>: Back to CircleCI -&gt; Click <a href="https://app.circleci.com/settings/organization/github/hinodelabo/overview?return-to=https%3A%2F%2Fapp.circleci.com%2Fpipelines%2Fgithub%2Fhinodelabo%2Fqlear-v2-bot"><strong>Organization Settings -&gt; Contexts -&gt; Create Context</strong></a></p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="541" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-13.15.01-2-1024x541.png" alt="" class="wp-image-1929" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-13.15.01-2-1024x541.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-13.15.01-2-300x158.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-13.15.01-2-768x406.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-13.15.01-2-1536x811.png 1536w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-13.15.01-2-380x201.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-13.15.01-2-800x423.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-13.15.01-2-1160x613.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-13.15.01-2.png 1600w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p><strong>Step 10</strong>: Enter name <strong>Context</strong> and click <strong>Create Context</strong></p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="480" height="337" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-13.21.17-1.png" alt="" class="wp-image-1930" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-13.21.17-1.png 480w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-13.21.17-1-300x211.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-13.21.17-1-200x140.png 200w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-13.21.17-1-380x267.png 380w" sizes="auto, (max-width: 480px) 100vw, 480px" /></figure>



<p><strong>Step 11</strong>: Click Context Name created and add environment for project such as <strong>RAILS_MASTER_KEY</strong>, <strong>RAILS_ENV</strong>, <strong>RACK_ENV</strong>, <strong>DANGER_GITHUB_API_TOKEN</strong></p>



<p><img loading="lazy" decoding="async" width="602" height="369" src="https://lh7-us.googleusercontent.com/17QyXLD3bPoW37cSOYqHPLsPm0uKHPu6OeuHKJdiNjW0BYHRYPnPjpcAqA5T76mSrD8TWG-LWkKGXCnG3C4I38vCi4Cd7omWGvVoAaEupr0jK01mlqi-yk3ejp44tmiIINx_DKnS1ZlCYgSS2hvmkA"></p>



<p>Click Add Environment and enter value as below:</p>



<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/VawQSbkEyRNPF0gTcuZpOMupCXkMWjkHYUkubeARhEFwjAtprXU7dO_uB1kJj_arFhyvmuBcOROKFznmQ20Z17xrc4TPQYJAtPGN9vP8u6IuuAJtv8jbnzBHktucj95hNV1ngdzhq6uqiyO7CVnMpA" alt=""/></figure>



<p><strong>Note:</strong></p>



<ul class="wp-block-list">
<li>RAILS_MASTER_KEY: Open file config/crendentials/test.key on project and copy it.</li>



<li>RAILS_ENV: test</li>



<li>RACK_ENV: test</li>
</ul>



<p>After add 3 environments, it will displayed as below:</p>



<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/WiT33geUhW0yOKFsk__sCQAGncXWsmc2gYABWVxVpEFs1loyoiC2nswh9C3YwTovzG9umpGJqqHC_uIf455XlXv5T8LRER2VQKr6JSDhRT4TeAmHii1cJrkZ2MrPnwm6FjBB_DzUdZC3i3QzuqpMsw" alt=""/></figure>



<p><strong>Step 12</strong>: Create <strong>DANGER_GITHUB_API_TOKEN</strong></p>



<ol class="wp-block-list">
<li>Access <a href="https://github.com/settings/tokens">https://github.com/settings/tokens</a> and click <strong>Generate new token</strong></li>
</ol>



<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/G8nn12MjFXdAlmZPbLyXC9j_FDpA4Mg1ES-R79AqjJo6rwp-QqaIWbWbwgWo678Jx2qUMSY8DqvkQehGEYDwLeR5eLddtBcirZmUMXvGYOSuMHqEi35NP7Da1p0TYW-dn0UBHUmod9FEVhM8qlCoAw" alt=""/></figure>



<ol class="wp-block-list" start="2">
<li>Write Note and Select Expiration, Scope. I choose Expiration 90 days and click repo</li>
</ol>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="776" height="388" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-13.43.20-1.png" alt="" class="wp-image-1934" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-13.43.20-1.png 776w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-13.43.20-1-300x150.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-13.43.20-1-768x384.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-13.43.20-1-380x190.png 380w" sizes="auto, (max-width: 776px) 100vw, 776px" /></figure>



<ol class="wp-block-list" start="3">
<li>Click Generate Token and Copy this.</li>
</ol>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="800" height="379" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-13.44.39-1.png" alt="" class="wp-image-1931" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-13.44.39-1.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-13.44.39-1-300x142.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-13.44.39-1-768x364.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-13.44.39-1-380x180.png 380w" sizes="auto, (max-width: 800px) 100vw, 800px" /></figure>



<ol class="wp-block-list" start="4">
<li>Back to <strong>Context</strong> and Add <strong>DANGER_GITHUB_API_TOKEN</strong></li>
</ol>



<p><strong>Step 12</strong>: Push code and runnnnn</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="287" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-14.23.09-1-1024x287.png" alt="" class="wp-image-1933" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-14.23.09-1-1024x287.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-14.23.09-1-300x84.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-14.23.09-1-768x216.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-14.23.09-1-1536x431.png 1536w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-14.23.09-1-380x107.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-14.23.09-1-800x225.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-14.23.09-1-1160x326.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-14.23.09-1.png 1600w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="931" height="497" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-14.23.43.png" alt="" class="wp-image-1936" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-14.23.43.png 931w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-14.23.43-300x160.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-14.23.43-768x410.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-14.23.43-380x203.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/Screen-Shot-2023-07-18-at-14.23.43-800x427.png 800w" sizes="auto, (max-width: 931px) 100vw, 931px" /></figure>
<p>The post <a href="https://blog.tomosia.com.vn/ror-huong-dan-setup-circleci-code-quality/">[ROR] Hướng dẫn setup CircleCI &#038; Code Quality</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.tomosia.com.vn/ror-huong-dan-setup-circleci-code-quality/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>Generating Image Thumbnails in Your Rails Application with CarrierWave</title>
		<link>https://blog.tomosia.com.vn/generating-image-thumbnails-in-your-rails-application-with-carrierwave/</link>
					<comments>https://blog.tomosia.com.vn/generating-image-thumbnails-in-your-rails-application-with-carrierwave/#comments</comments>
		
		<dc:creator><![CDATA[Hổ Nguyễn]]></dc:creator>
		<pubDate>Wed, 15 Nov 2023 09:43:26 +0000</pubDate>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby On Rails]]></category>
		<guid isPermaLink="false">https://blog.tomosia.com.vn/?p=1853</guid>

					<description><![CDATA[<p>Bạn đang xây dựng một ứng dụng web trong Rails và muốn cung cấp cho người dùng khả&#8230;</p>
<p>The post <a href="https://blog.tomosia.com.vn/generating-image-thumbnails-in-your-rails-application-with-carrierwave/">Generating Image Thumbnails in Your Rails Application with CarrierWave</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Bạn đang xây dựng một ứng dụng web trong Rails và muốn cung cấp cho người dùng khả năng tải lên và quản lý hình ảnh một cách dễ dàng? Gem CarrierWave là một lựa chọn tuyệt vời giúp bạn thực hiện điều này một cách hiệu quả. Trong bài viết này, chúng ta sẽ khám phá cách sử dụng CarrierWave để tải ảnh trong ứng dụng Rails của bạn.</p>



<h2 id="1-gioi-thieu-ve-carrierwave" class="wp-block-heading" style="font-size:28px;font-style:normal;font-weight:400"><strong>1. Giới Thiệu Về CarrierWave</strong></h2>



<p>CarrierWave là một gem Ruby on Rails mạnh mẽ được thiết kế để giúp bạn quản lý và xử lý tệp tin tải lên, đặc biệt là ảnh. Với tính năng linh hoạt và dễ sử dụng, CarrierWave giúp bạn dễ dàng thay đổi kích thước ảnh, lưu trữ trên các dịch vụ như Amazon S3, và thậm chí cả tạo các phiên bản ảnh thumbnail.</p>



<h2 id="2-cai-dat-carrierwave" class="wp-block-heading" style="font-size:28px;font-style:normal;font-weight:400"><strong>2. Cài Đặt CarrierWave</strong></h2>



<p>Để bắt đầu, thêm gem CarrierWave vào Gemfile của bạn:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Bash</span><span role="button" tabindex="0" data-code="gem 'carrierwave'
" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #62E884">gem</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">carrierwave</span><span style="color: #DEE492">&#39;</span></span>
<span class="line"></span></code></pre></div>



<p>Sau đó, cài đặt và sinh ra file cấu hình:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Bash</span><span role="button" tabindex="0" data-code="bundle install
rails generate uploader Avatar
" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #62E884">bundle</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">install</span></span>
<span class="line"><span style="color: #62E884">rails</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">generate</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">uploader</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">Avatar</span></span>
<span class="line"></span></code></pre></div>



<h2 id="3-su-dung-carrierwave-trong-model" class="wp-block-heading" style="font-size:28px;font-style:normal;font-weight:400"><strong>3. Sử Dụng CarrierWave Trong Model</strong></h2>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Ruby</span><span role="button" tabindex="0" data-code="class User < ApplicationRecord
  mount_uploader :avatar, AvatarUploader
end
" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">class</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">User</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">&lt;</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">ApplicationRecord</span></span>
<span class="line"><span style="color: #F6F6F4">  mount_uploader </span><span style="color: #BF9EEE">:avatar</span><span style="color: #F6F6F4">, </span><span style="color: #BF9EEE">AvatarUploader</span></span>
<span class="line"><span style="color: #F286C4">end</span></span>
<span class="line"></span></code></pre></div>



<p>Ở đây, <strong><code>avatar</code></strong> là tên của trường chứa đường dẫn đến tệp tin đã được tải lên, và <strong><code>AvatarUploader</code></strong> là tên của uploader đã được sinh ra trước đó.</p>



<h2 id="4-xu-ly-anh-trong-controller" class="wp-block-heading" style="font-size:28px;font-style:normal;font-weight:400"><strong>4. Xử Lý Ảnh Trong Controller</strong></h2>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Ruby</span><span role="button" tabindex="0" data-code="class UsersController < ApplicationController
  def update
    @user = User.find(params[:id])
    @user.update(user_params)
  end

  private

  def user_params
    params.require(:user).permit(:avatar)
  end
end
" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">class</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">UsersController</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">&lt;</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">ApplicationController</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #F286C4">def</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">update</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #BF9EEE; font-style: italic">@user</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">User</span><span style="color: #F6F6F4">.find(params[</span><span style="color: #BF9EEE">:id</span><span style="color: #F6F6F4">])</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #BF9EEE; font-style: italic">@user</span><span style="color: #F6F6F4">.update(user_params)</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #F286C4">end</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #F286C4">private</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #F286C4">def</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">user_params</span></span>
<span class="line"><span style="color: #F6F6F4">    params.require(</span><span style="color: #BF9EEE">:user</span><span style="color: #F6F6F4">).permit(</span><span style="color: #BF9EEE">:avatar</span><span style="color: #F6F6F4">)</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #F286C4">end</span></span>
<span class="line"><span style="color: #F286C4">end</span></span>
<span class="line"></span></code></pre></div>



<h2 id="5-hien-thi-anh-trong-view" class="wp-block-heading" style="font-size:28px;font-style:normal;font-weight:400"><strong>5. Hiển Thị Ảnh Trong View</strong></h2>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Ruby</span><span role="button" tabindex="0" data-code="<%= image_tag @user.avatar.url if @user.avatar.present? %&gt;
" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">&lt;%=</span><span style="color: #F6F6F4"> image_tag </span><span style="color: #BF9EEE; font-style: italic">@user</span><span style="color: #F6F6F4">.avatar.url </span><span style="color: #F286C4">if</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE; font-style: italic">@user</span><span style="color: #F6F6F4">.avatar.present? </span><span style="color: #DEE492">%&gt;</span></span>
<span class="line"></span></code></pre></div>



<h2 id="6-tinh-nang-mo-rong" class="wp-block-heading" style="font-size:28px;font-style:normal;font-weight:400"><strong>6. Tính Năng Mở Rộng</strong></h2>



<p>CarrierWave cho phép bạn thực hiện nhiều tính năng hấp dẫn như:</p>



<ul class="wp-block-list">
<li><strong>Thay Đổi Kích Thước Ảnh:</strong> </li>
</ul>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Ruby</span><span role="button" tabindex="0" data-code="# Trong AvatarUploader
version :thumb do
  process resize_to_fill: [150, 150]
end" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #7B7F8B"># Trong AvatarUploader</span></span>
<span class="line"><span style="color: #F6F6F4">version </span><span style="color: #BF9EEE">:thumb</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">do</span></span>
<span class="line"><span style="color: #F6F6F4">  process resize_to_fill</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> [</span><span style="color: #BF9EEE">150</span><span style="color: #F6F6F4">, </span><span style="color: #BF9EEE">150</span><span style="color: #F6F6F4">]</span></span>
<span class="line"><span style="color: #F286C4">end</span></span></code></pre></div>



<ul class="wp-block-list">
<li><strong>Lưu Trữ Trên S3:</strong> </li>
</ul>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Ruby</span><span role="button" tabindex="0" data-code="# Trong config/initializers/carrierwave.rb
config.fog_credentials = {
  provider: 'AWS',
  aws_access_key_id: 'your_access_key',
  aws_secret_access_key: 'your_secret_key',
  region: 'your_region'
}

config.fog_directory = 'your_bucket_name'" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #7B7F8B"># Trong config/initializers/carrierwave.rb</span></span>
<span class="line"><span style="color: #F6F6F4">config.fog_credentials </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  provider</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">AWS</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">  aws_access_key_id</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">your_access_key</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">  aws_secret_access_key</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">your_secret_key</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">  region</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">your_region</span><span style="color: #DEE492">&#39;</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">config.fog_directory </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">your_bucket_name</span><span style="color: #DEE492">&#39;</span></span></code></pre></div>



<h2 id="7-ket-luan" class="wp-block-heading" style="font-size:28px;font-style:normal;font-weight:400">7. Kết Luận</h2>



<p>Gem CarrierWave không chỉ giúp bạn dễ dàng quản lý tệp tin tải lên mà còn mở ra nhiều khả năng mở rộng. Sử dụng nó để tối ưu hóa trải nghiệm người dùng trong ứng dụng Rails của bạn và tận dụng tất cả những tính năng mà nó mang lại. Happy coding!</p>
<p>The post <a href="https://blog.tomosia.com.vn/generating-image-thumbnails-in-your-rails-application-with-carrierwave/">Generating Image Thumbnails in Your Rails Application with CarrierWave</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.tomosia.com.vn/generating-image-thumbnails-in-your-rails-application-with-carrierwave/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>An Introduction to the ViewComponent Gem</title>
		<link>https://blog.tomosia.com.vn/an-introduction-to-the-viewcomponent-gem/</link>
					<comments>https://blog.tomosia.com.vn/an-introduction-to-the-viewcomponent-gem/#comments</comments>
		
		<dc:creator><![CDATA[tung nguyen]]></dc:creator>
		<pubDate>Tue, 14 Nov 2023 09:57:07 +0000</pubDate>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby On Rails]]></category>
		<category><![CDATA[Rails]]></category>
		<guid isPermaLink="false">https://blog.tomosia.com.vn/?p=1404</guid>

					<description><![CDATA[<p>Được truyền cảm hứng từ React, ViewComponent là các đối tượng Ruby được sử dụng để xây dựng&#8230;</p>
<p>The post <a href="https://blog.tomosia.com.vn/an-introduction-to-the-viewcomponent-gem/">An Introduction to the ViewComponent Gem</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Được truyền cảm hứng từ React, ViewComponent là các đối tượng Ruby được sử dụng để xây dựng đánh dấu cho việc hiển thị các view. ViewComponent là một framework cho việc xây dựng các thành phần view có thể tái sử dụng, kiểm thử và đóng gói trong Rails. Thông thường, các view có thể tái sử dụng được tạo trong Rails bằng cách sử dụng partials (đoạn mã HTML tái sử dụng) và sau đó được hiển thị trong các view khác khi cần, nhưng với sự giới thiệu của ViewComponent gem, partials có thể được thay thế bằng các thành phần view, vì chúng cung cấp nhiều lợi ích hơn. Hãy tìm hiểu về những lợi ích này.</p>



<p><strong>Khi nào và tại sao nên sử dụng view component</strong>?</p>



<p>Như đã nêu trước đó, các thành phần view là có thể tái sử dụng và có thể kiểm thử. Do đó, chúng có thể được áp dụng khi một view cần được tái sử dụng hoặc có lợi từ việc được kiểm thử trực tiếp. Một số lợi ích của các thành phần view, như đã nêu trong tài liệu của chúng, bao gồm các điểm sau:<br></p>



<ul class="wp-block-list">
<li>Chúng nhanh gấp đôi (khoảng 10 lần) so với partials.</li>



<li>là các đối tượng Ruby, do đó, phương thức khởi tạo của chúng rõ ràng xác định những gì cần thiết để hiển thị một view. Điều này có nghĩa là chúng dễ hiểu hơn và có thể tái sử dụng trong nhiều view khác nhau. Hơn nữa, các tiêu chuẩn chất lượng mã Ruby có thể được áp dụng, giúp giảm rủi ro của lỗi.</li>



<li>có thể được kiểm thử đơn vị, trong khi các view truyền thống của Rails yêu cầu kiểm thử tích hợp, cũng bao gồm việc thực hiện routing và controller ngoài việc hiển thị view.</li>
</ul>



<p><strong>Triển khai viewcomponent</strong></p>



<p>Các ViewComponent là các lớp con của <span style="color: red">ViewComponent::Base</span> và được đặt trong thư mục app/components. Tên của chúng kết thúc bằng &#8211; Component và nên được đặt theo cái mà chúng hiển thị chứ không phải cái mà chúng nhận. Chúng ta có thể tạo một view component bằng cách thủ công hoặc thông qua trình tạo component, nhưng trước tiên chúng ta cần thêm gem vào file gemfile và chạy lệnh bundle install.</p>



<pre class="wp-block-code"><code>gem "view_component"</code></pre>



<p>Để sử dụng trình tạo, chạy lệnh sau đây:</p>



<pre class="wp-block-code"><code>rails generate component &lt;Component name&gt; &lt;arguments needed for initialization&gt;</code></pre>



<p>Ví dụ, nếu chúng ta muốn tạo một component để hiển thị danh sách các khóa học trong lớp có sẵn trên một nền tảng học tập, chúng ta có thể sử dụng lệnh sau đây:</p>



<pre class="wp-block-code"><code>rails g component Course course</code></pre>



<p>Chúng ta đang truyền đối số&nbsp;<code>course</code>&nbsp;vào lệnh này vì chúng ta sẽ khởi tạo đối tượng Ruby này với khóa học mà chúng ta mong muốn nó hiển thị, và chúng ta đã đặt tên là&nbsp;<code>Course</code>&nbsp;vì nó hiển thị một khóa học.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="635" height="119" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-3.png" alt="" class="wp-image-1797" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-3.png 635w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-3-300x56.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-3-380x71.png 380w" sizes="auto, (max-width: 635px) 100vw, 635px" /></figure>



<p>Như chúng ta có thể thấy ở trên, component và file html tương ứng được tạo trong thư mục app/components, cùng với một file test</p>



<p>ViewComponent bao gồm các bộ tạo mẫu cho các công cụ mẫu erb, haml và slim, nhưng sẽ mặc định theo công cụ mẫu được chỉ định trong config.generators.template_engine. Tuy nhiên, bạn có thể chỉ định công cụ mẫu mong muốn bằng cách sử dụng các câu lệnh sau:</p>



<pre class="wp-block-code"><code>rails generate component Course course --template-engine &lt;your template engine&gt;</code></pre>



<p>Tiếp theo, chúng ta sẽ tạo model&nbsp;<code>Course</code>&nbsp;và một số khóa học để hiển thị.</p>



<pre class="wp-block-code"><code>rails g model Course title:string price:decimal location:string
rails db:migrate
</code></pre>



<p>Tạo hai khóa học mẫu:</p>



<pre class="wp-block-code"><code>Course.create(title: 'The Art of Learning', price: 125.00, location: 'Denmark')
Course.create(title: 'Organizing your Time', price: 55.00, location: 'London')</code></pre>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="204" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-5-1024x204.png" alt="" class="wp-image-1799" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-5-1024x204.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-5-300x60.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-5-768x153.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-5-1536x306.png 1536w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-5-380x76.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-5-800x159.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-5-1160x231.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-5.png 1844w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Tệp&nbsp;<code>course_component.rb</code>&nbsp;được tạo ra với phương thức&nbsp;<code>initialize</code>&nbsp; được hiển thị dưới đây.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="686" height="307" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-4.png" alt="" class="wp-image-1798" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-4.png 686w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-4-300x134.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-4-380x170.png 380w" sizes="auto, (max-width: 686px) 100vw, 686px" /></figure>



<p>Tiếp theo là tạo controller và routes</p>



<pre class="wp-block-code"><code>rails g controller Courses index</code></pre>



<p>chỉnh sửa root của trang</p>



<pre class="wp-block-code"><code>root 'courses#index'</code></pre>



<p>Tạo giao diện, viêc tạo giao diện được thiện hiện ở file <code>course_component.html.erb</code>. mà chúng ta đã gen ở trước đó.<code><br></code></p>



<pre class="wp-block-code"><code><code>&lt;div&gt;
  &lt;h2&gt;&lt;%= @course.title %&gt;&lt;/h2&gt;
  &lt;h4&gt;&lt;%=  number_to_currency(@course.price, :unit =&gt; "€") %&gt;&lt;/h4&gt;
  &lt;h4&gt;&lt;%= @course.location %&gt;&lt;/h4&gt;
&lt;/div&gt;</code></code></pre>



<p>ở view, chúng ta hiển thị tiêu đề khóa học, giá và địa điểm sử dụng biến&nbsp;<code>@course</code>, đã được định nghĩa trong phương thức&nbsp;<code>initialize</code>&nbsp;của&nbsp;<code>CourseComponent</code>. Điều này tương tự khi tạo một biến trong một method ở controller và sau đó nó sẽ có sẵn trong một giao diện.</p>



<p>để biết cách controller hoạt động thì chuyển đến trang <em>index.html.erb</em> với method index tương ứng ở controller. ở đây chúng ta sẽ render component</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="756" height="141" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-6.png" alt="" class="wp-image-1800" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-6.png 756w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-6-300x56.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-6-380x71.png 380w" sizes="auto, (max-width: 756px) 100vw, 756px" /></figure>



<p>Như đã thấy ở trên, chúng ta render new instance của&nbsp;<code>CourseComponent</code>&nbsp;bằng cách khởi tạo courseComponent với khóa học mà chúng ta muốn nó hiển thị trong giao diện index course. Khóa học này trở thành biến&nbsp;<code>@course</code>&nbsp;được cung cấp cho tệp&nbsp;<code>course_component.html.erb</code>.</p>



<p>Chúng ta có thể render trực tiếp ở controller như sau</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="752" height="222" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-7.png" alt="" class="wp-image-1801" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-7.png 752w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-7-300x89.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-7-380x112.png 380w" sizes="auto, (max-width: 752px) 100vw, 752px" /></figure>



<p>Nội dung bổ sung cũng có thể được truyền vào component theo một trong những cách sau đây:</p>



<pre class="wp-block-code"><code>&lt;%= render(CourseComponent.new(course: Course.find(1))) do %&gt;
  container
&lt;% end %&gt;
&lt;%= render(CourseComponent.new(course: Course.find(1)).with_content("container")) %&gt;</code></pre>



<p>Trong file component, chúng ta có thể include nội dung ở bất kỳ đâu mà chúng ta muốn. Trong trường hợp này, chúng ta sẽ thêm content như một class bằng cách chỉnh sửa thẻ div như sau:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="900" height="293" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-8.png" alt="" class="wp-image-1812" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-8.png 900w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-8-300x98.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-8-768x250.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-8-380x124.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-8-800x260.png 800w" sizes="auto, (max-width: 900px) 100vw, 900px" /></figure>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="491" height="128" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-9.png" alt="" class="wp-image-1813" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-9.png 491w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-9-300x78.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-9-380x99.png 380w" sizes="auto, (max-width: 491px) 100vw, 491px" /></figure>



<p><strong>Render a Collection</strong></p>



<p>Nếu chúng ta muốn hiển thị toàn bộ danh sách các khóa học, ViewComponent cung cấp một cách rất đơn giản để làm điều này bằng cách sử dụng method with_collection. Thay vì khởi tạo component bằng cách sử dụng .new, nó được khởi tạo bằng cách sử dụng .with_collection, và collection được truyền vào như một biến</p>



<pre class="wp-block-code"><code>CourseComponent.with_collection(Course.all)</code></pre>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="576" height="282" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-11.png" alt="" class="wp-image-1815" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-11.png 576w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-11-300x147.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-11-380x186.png 380w" sizes="auto, (max-width: 576px) 100vw, 576px" /></figure>



<p>&nbsp;thẻ&nbsp;<code>with_collection_parameter</code>&nbsp;có sẵn trong trường hợp chúng ta muốn đặt tên khác cho bộ sưu tập.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="631" height="316" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-12.png" alt="" class="wp-image-1816" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-12.png 631w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-12-300x150.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-12-380x190.png 380w" sizes="auto, (max-width: 631px) 100vw, 631px" /></figure>



<p>Trong trường hợp trên, tham số của khóa học đã được đặt tên là &#8220;item&#8221;. Do đó, trong tệp xem tương ứng, &#8220;@course&#8221; sẽ được thay thế bằng &#8220;@item&#8221; để được kết quả tương tự.</p>



<p>Các tham số bổ sung cũng có thể được thêm vào collection. Các tham số này sẽ được hiển thị cho mỗi mục trong collection. Hãy thêm văn bản &#8220;Buy Me&#8221; vào mỗi mục thông qua phương thức này.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="868" height="127" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-13.png" alt="" class="wp-image-1818" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-13.png 868w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-13-300x44.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-13-768x112.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-13-380x56.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-13-800x117.png 800w" sizes="auto, (max-width: 868px) 100vw, 868px" /></figure>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="804" height="311" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-14.png" alt="" class="wp-image-1819" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-14.png 804w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-14-300x116.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-14-768x297.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-14-380x147.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-14-800x309.png 800w" sizes="auto, (max-width: 804px) 100vw, 804px" /></figure>



<p>thêm @noitce vào file course_component.html.erb</p>



<pre class="wp-block-code"><code>&lt;p&gt;&lt;a href='#'&gt; &lt;%= @notice %&gt; &lt;/a&gt;&lt;/p&gt;</code></pre>



<p>Cuối cùng, trong tùy chọn&nbsp;<code>collections</code>, chúng ta có một biến đếm (<code>counter variable</code>) có thể được kích hoạt để đánh số các mục. Để kích hoạt biến đếm này, chúng ta cần thêm &#8220;_counter&#8221; vào tham số của bộ sưu tập và làm cho nó có sẵn trong các tệp xem thông qua phương thức&nbsp;<code>initialize</code>.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="658" height="298" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-15.png" alt="" class="wp-image-1820" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-15.png 658w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-15-300x136.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-15-380x172.png 380w" sizes="auto, (max-width: 658px) 100vw, 658px" /></figure>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="437" height="369" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-16.png" alt="" class="wp-image-1821" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-16.png 437w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-16-300x253.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-16-380x321.png 380w" sizes="auto, (max-width: 437px) 100vw, 437px" /></figure>



<p>Xem bài viết đầy đủ tại đây: https://www.honeybadger.io/blog/ruby-view-components/</p>



<p>Thank you!!! </p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>
<p>The post <a href="https://blog.tomosia.com.vn/an-introduction-to-the-viewcomponent-gem/">An Introduction to the ViewComponent Gem</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.tomosia.com.vn/an-introduction-to-the-viewcomponent-gem/feed/</wfw:commentRss>
			<slash:comments>7</slash:comments>
		
		
			</item>
	</channel>
</rss>
