<?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>NST, Author at Tomoshare</title>
	<atom:link href="https://blog.tomosia.com.vn/author/tungsonnguyen/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.tomosia.com.vn/author/tungsonnguyen/</link>
	<description>Kênh chia sẻ kiến thức Tomosia Việt Nam</description>
	<lastBuildDate>Tue, 02 Jan 2024 07:49:20 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>

<image>
	<url>https://blog.tomosia.com.vn/wp-content/uploads/2023/09/cropped-icon-32x32.png</url>
	<title>NST, Author at Tomoshare</title>
	<link>https://blog.tomosia.com.vn/author/tungsonnguyen/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<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[Rails]]></category>
		<category><![CDATA[Ruby On 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 fetchpriority="high" 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 class="wp-block-paragraph">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 class="wp-block-paragraph">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 class="wp-block-paragraph">Đầ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 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="(max-width: 1015px) 100vw, 1015px" /></figure>



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



<p class="wp-block-paragraph">Đầ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 class="wp-block-paragraph">Hi vọng bài viết sẽ giúp ích được mọi người.</p>



<p class="wp-block-paragraph">Cảm ơn mọi người.</p>



<p class="wp-block-paragraph"></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>5</slash:comments>
		
		
			</item>
		<item>
		<title>Hiểu hơn về method Uniq trong Ruby</title>
		<link>https://blog.tomosia.com.vn/hieu-hon-ve-method-uniq-trong-ruby/</link>
					<comments>https://blog.tomosia.com.vn/hieu-hon-ve-method-uniq-trong-ruby/#comments</comments>
		
		<dc:creator><![CDATA[NST]]></dc:creator>
		<pubDate>Wed, 29 Nov 2023 04:04:56 +0000</pubDate>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Kinh nghiệm]]></category>
		<guid isPermaLink="false">https://blog.tomosia.com.vn/?p=2007</guid>

					<description><![CDATA[<p>Hầu như tất cả mọi người đã biết method uniq được sử dụng với mục đích để xoá&#8230;</p>
<p>The post <a href="https://blog.tomosia.com.vn/hieu-hon-ve-method-uniq-trong-ruby/">Hiểu hơn về method Uniq trong Ruby</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Hầu như tất cả mọi người đã biết method <strong>uniq</strong> được sử dụng với mục đích để xoá những phần tử trùng nhau trong 1 array.</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="n = [1,1,1,2,3,4,5]
n.uniq
# [1,2,3,4,5]" 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">n </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> [</span><span style="color: #BF9EEE">1</span><span style="color: #F6F6F4">,</span><span style="color: #BF9EEE">1</span><span style="color: #F6F6F4">,</span><span style="color: #BF9EEE">1</span><span style="color: #F6F6F4">,</span><span style="color: #BF9EEE">2</span><span style="color: #F6F6F4">,</span><span style="color: #BF9EEE">3</span><span style="color: #F6F6F4">,</span><span style="color: #BF9EEE">4</span><span style="color: #F6F6F4">,</span><span style="color: #BF9EEE">5</span><span style="color: #F6F6F4">]</span></span>
<span class="line"><span style="color: #F6F6F4">n.uniq</span></span>
<span class="line"><span style="color: #7B7F8B"># [1,2,3,4,5]</span></span></code></pre></div>



<p class="wp-block-paragraph">Tuy nhiên, đối với những mảng phức tạp hơn, hoặc <strong>uniq</strong> theo điều kiện cụ thể thì mọi người sẽ đa số sẽ sử dụng <strong>loop in loop</strong> hoặc thử bất cứ thứ gì mọi người tìm được trên <em><strong>Stack Overflow</strong></em> thay vì vào document để tìm giải pháp. Mình cũng như thế và hầu như là đều như thế =))</p>



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



<p class="wp-block-paragraph">Vào một ngày đẹp trời và KH thay đổi spec muốn mình uniq những users có cùng score và local. Sau tỉ tỉ vòng lặp và vô số lần nghi ngờ thì mình lại vào document và tìm được giải pháp có thể giải quyết vấn đề của mình. =))</p>



<p class="wp-block-paragraph">Chắc mình cũng sẽ dần dần thay đổi mindset ở trên vì mình cảm thấy như thế sẽ tốt hơn với mình =))</p>



<p class="wp-block-paragraph">Lan man quá lâu rồi chúng ta quay lại phần chính nha.</p>



<p class="wp-block-paragraph">Nhiều người chưa biết rằng <strong>uniq</strong> có thể được sử dụng như 1 block, do đó bạn có sử dụng <strong>uniq</strong> nâng cao hơn.</p>



<p class="wp-block-paragraph"><strong>Uniq With Multiple Conditions</strong></p>



<ul class="wp-block-list">
<li>Có thể sử dụng nhiều điều kiện đối với 1 mảng hash!</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: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="users = [{name: 'a1', score: 1, local: 'danang'}, 
					{name: 'a2', score: 1, local: 'danang'},
					{name: 'a3', score: 1, local: 'danang'},
					{name: 'a4', score: 2, local: 'hanoi'},
					{name: 'a5', score: 2, local: 'hanoi'},
					{name: 'a6', score: 3, local: 'hanoi'}
				]

users.uniq { |user| [user[:score], user[:local]] }

#OUTPUT:
[{:name=&gt;&quot;a1&quot;, :score=&gt;1, :local=&gt;&quot;danang&quot;},
 {:name=&gt;&quot;a4&quot;, :score=&gt;2, :local=&gt;&quot;hanoi&quot;},
 {:name=&gt;&quot;a6&quot;, :score=&gt;3, :local=&gt;&quot;hanoi&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: #F6F6F4">users </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> [{name</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">a1</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">, score</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">1</span><span style="color: #F6F6F4">, local</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">danang</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">}, </span></span>
<span class="line"><span style="color: #F6F6F4">					{name</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">a2</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">, score</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">1</span><span style="color: #F6F6F4">, local</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">danang</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">},</span></span>
<span class="line"><span style="color: #F6F6F4">					{name</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">a3</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">, score</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">1</span><span style="color: #F6F6F4">, local</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">danang</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">},</span></span>
<span class="line"><span style="color: #F6F6F4">					{name</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">a4</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">, score</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">2</span><span style="color: #F6F6F4">, local</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">hanoi</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">},</span></span>
<span class="line"><span style="color: #F6F6F4">					{name</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">a5</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">, score</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">2</span><span style="color: #F6F6F4">, local</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">hanoi</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">},</span></span>
<span class="line"><span style="color: #F6F6F4">					{name</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">a6</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">, score</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">3</span><span style="color: #F6F6F4">, local</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">hanoi</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 style="color: #F6F6F4">users.uniq { |user| [user[</span><span style="color: #BF9EEE">:score</span><span style="color: #F6F6F4">], user[</span><span style="color: #BF9EEE">:local</span><span style="color: #F6F6F4">]] }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #7B7F8B">#OUTPUT:</span></span>
<span class="line"><span style="color: #F6F6F4">[{</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4">name</span><span style="color: #F286C4">=&gt;</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">a1</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">, </span><span style="color: #F286C4">:</span><span style="color: #F6F6F4">score</span><span style="color: #F286C4">=&gt;</span><span style="color: #BF9EEE">1</span><span style="color: #F6F6F4">, </span><span style="color: #F286C4">:</span><span style="color: #F6F6F4">local</span><span style="color: #F286C4">=&gt;</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">danang</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">},</span></span>
<span class="line"><span style="color: #F6F6F4"> {</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4">name</span><span style="color: #F286C4">=&gt;</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">a4</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">, </span><span style="color: #F286C4">:</span><span style="color: #F6F6F4">score</span><span style="color: #F286C4">=&gt;</span><span style="color: #BF9EEE">2</span><span style="color: #F6F6F4">, </span><span style="color: #F286C4">:</span><span style="color: #F6F6F4">local</span><span style="color: #F286C4">=&gt;</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">hanoi</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">},</span></span>
<span class="line"><span style="color: #F6F6F4"> {</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4">name</span><span style="color: #F286C4">=&gt;</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">a6</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">, </span><span style="color: #F286C4">:</span><span style="color: #F6F6F4">score</span><span style="color: #F286C4">=&gt;</span><span style="color: #BF9EEE">3</span><span style="color: #F6F6F4">, </span><span style="color: #F286C4">:</span><span style="color: #F6F6F4">local</span><span style="color: #F286C4">=&gt;</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">hanoi</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">}]</span></span></code></pre></div>



<p class="wp-block-paragraph"><strong>Uniq Method With A Block</strong></p>



<ul class="wp-block-list">
<li>Bạn có thể đặt mọi thứ mà bạn nghĩ nó có thể dùng làm rules khi <strong>uniq.</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.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="fruits = %w(orange apple banana)
# 'Orange' and 'Apple' **length of 6 characters**

fruits.uniq(&amp;:size)
# [&quot;orange&quot;, &quot;apple&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: #F6F6F4">fruits </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">%</span><span style="color: #F6F6F4">w(orange apple banana)</span></span>
<span class="line"><span style="color: #7B7F8B"># &#39;Orange&#39; and &#39;Apple&#39; **length of 6 characters**</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">fruits.uniq(</span><span style="color: #F286C4">&amp;</span><span style="color: #BF9EEE">:size</span><span style="color: #F6F6F4">)</span></span>
<span class="line"><span style="color: #7B7F8B"># [&quot;orange&quot;, &quot;apple&quot;]</span></span></code></pre></div>



<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="objects = [1, 2, &quot;a&quot;, &quot;b&quot;, :c, :d]
# 1, 2 -&gt; Integer; 'a', 'b'-&gt; String; :c, :d -&gt; Symbol
 
objects.uniq(&amp;:class)
#[1, &quot;a&quot;, :c]
" 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">objects </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> [</span><span style="color: #BF9EEE">1</span><span style="color: #F6F6F4">, </span><span style="color: #BF9EEE">2</span><span style="color: #F6F6F4">, </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">a</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">, </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">b</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">, </span><span style="color: #BF9EEE">:c</span><span style="color: #F6F6F4">, </span><span style="color: #BF9EEE">:d</span><span style="color: #F6F6F4">]</span></span>
<span class="line"><span style="color: #7B7F8B"># 1, 2 -&gt; Integer; &#39;a&#39;, &#39;b&#39;-&gt; String; :c, :d -&gt; Symbol</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">objects.uniq(</span><span style="color: #F286C4">&amp;</span><span style="color: #BF9EEE">:class</span><span style="color: #F6F6F4">)</span></span>
<span class="line"><span style="color: #7B7F8B">#[1, &quot;a&quot;, :c]</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Qua bài viết, mình hi vọng có thể giúp bạn giải quyết được những vấn đề của bản thân trong tương lai.</p>



<p class="wp-block-paragraph">Cảm ơn vì đã đọc!</p>



<p class="wp-block-paragraph">Sources: <a href="https://www.rubyguides.com/2019/08/ruby-uniq-method/">https://www.rubyguides.com/2019/08/ruby-uniq-method/</a></p>
<p>The post <a href="https://blog.tomosia.com.vn/hieu-hon-ve-method-uniq-trong-ruby/">Hiểu hơn về method Uniq trong Ruby</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.tomosia.com.vn/hieu-hon-ve-method-uniq-trong-ruby/feed/</wfw:commentRss>
			<slash:comments>10</slash:comments>
		
		
			</item>
		<item>
		<title>Các nguyên tắc tốt nhất để lấy dữ liệu trên Website mà không bị chặn</title>
		<link>https://blog.tomosia.com.vn/cac-nguyen-tac-tot-nhat-de-lay-du-lieu-tren-website-ma-khong-bi-chan/</link>
					<comments>https://blog.tomosia.com.vn/cac-nguyen-tac-tot-nhat-de-lay-du-lieu-tren-website-ma-khong-bi-chan/#comments</comments>
		
		<dc:creator><![CDATA[NST]]></dc:creator>
		<pubDate>Wed, 25 Oct 2023 02:49:44 +0000</pubDate>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Kinh nghiệm]]></category>
		<guid isPermaLink="false">https://blog.tomosia.com.vn/?p=1494</guid>

					<description><![CDATA[<p>Dữ liệu là “tài sản” quan trọng của &#8220;Business production”. Tuy nhiên, để tiết kiệm chi phí hoặc&#8230;</p>
<p>The post <a href="https://blog.tomosia.com.vn/cac-nguyen-tac-tot-nhat-de-lay-du-lieu-tren-website-ma-khong-bi-chan/">Các nguyên tắc tốt nhất để lấy dữ liệu trên Website mà không bị chặn</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><em>Dữ liệu là “tài sản” quan trọng của &#8220;<strong>Business production</strong>”. Tuy nhiên, để tiết kiệm chi phí hoặc để thu thập dữ liệu từ những nguồn mà bạn muốn để phục vụ công việc của bản thân thì việc “<strong>Scrape”</strong> là việc bắt buộc.</em></p>



<p class="wp-block-paragraph"><em>Mặc dù việc thu thập dữ liệu trên các trang web nhỏ hiếm khi dẫn đến sự cố về việc thu thập dữ liệu nhưng khi bạn bắt đầu thu thập dữ liệu trên các trang web lớn hơn những trang web có cơ chế chống <strong>“Scrape” .</strong></em></p>



<p class="wp-block-paragraph">Bản thân mình cũng đã được trải nghiệm cảm giác này. Nó rất là CAY, cảm thấy bất lực và tồi tệ.</p>



<p class="wp-block-paragraph">Trong bài viết này, mình sẽ chia sẻ một số phương pháp hay nhất về việc <strong>“đục”</strong> web để tránh việc bị chặn trong tương lai. Hi vọng nó sẽ hữu ích với bạn.</p>



<h3 id="1-use-ip-rotation" class="wp-block-heading"><strong>1. Use IP Rotation</strong></h3>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="615" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/10/Untitled-1024x615.png" alt="" class="wp-image-1495" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Untitled-1024x615.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Untitled-300x180.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Untitled-768x461.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Untitled-380x228.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Untitled-560x336.png 560w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Untitled-800x481.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Untitled.png 1160w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Việc request lặp lại từ cùng một địa chỉ IP là dấu hiệu rõ ràng cho thấy bạn đang tự động hóa các request HTTPS/HTTP lên sever của họ. Người sở hữu có thể phát hiện và chặn IP của bạn bằng cách kiểm tra địa chỉ IP trong server log.</p>



<p class="wp-block-paragraph">Hiện nay, có nhiều đơn vụ cung cấp dịch vụ này một cách tự động do đó không quá khăn để họ có thể ngăn chặn bạn.</p>



<p class="wp-block-paragraph"><strong>Giải pháp:</strong> Hãy sử dụng <strong>Proxy Sever</strong> hoặc <strong>VPN</strong> để gửi request của bạn thông qua một loạt địa chỉ IP khác nhau. IP thực của bạn sẽ bị ẩn. Theo đó, bạn sẽ có thể quét hầu hết các trang web mà không gặp vấn đề gì.</p>



<p class="wp-block-paragraph">Recommend: <strong>Nord VPN</strong> (mình đã sài thằng này để giải quyết bài toán của mình), ngoài ra có thể sử dụng bất kì VPN nào bạn thấy phụ hợp.</p>



<h3 id="2-set-additional-request-headers" class="wp-block-heading">2. <strong>Set Additional Request Headers</strong></h3>



<p class="wp-block-paragraph">Các browsers (<strong>real)</strong> sẽ có rất nhiều headers khác nhau, bất kỳ headers nào trong số này có thể được các trang web kiểm tra để chặn request của bạn.</p>



<p class="wp-block-paragraph">Thường thì bạn sẽ không có <strong>Request Headers</strong> khi <em>“<strong>Scrape” .</strong></em></p>



<p class="wp-block-paragraph"><strong>Giải pháp:</strong> Do đó, để làm cho trình quét web của bạn trông <strong>real</strong> hơn, bạn hãy thêm vào nhé.</p>



<p class="wp-block-paragraph">Bạn có thể sao chép tất cả các tiêu đề từ <a href="http://httpbin.org/anything">httpbin.org/anything</a>. (Đây là những tiêu đề mà trình duyệt của bạn hiện đang sử dụng).</p>



<p class="wp-block-paragraph">Hoặc có thể vào <a href="https://intoli.com/blog/not-possible-to-block-chrome-headless/chrome-headless-test.html">https://intoli.com/blog/not-possible-to-block-chrome-headless/chrome-headless-test.html</a> để kiểm tra.</p>



<h3 id="3-set-a-referrer" class="wp-block-heading">3. <strong>Set A Referrer</strong></h3>



<p class="wp-block-paragraph">Referrer header là http request header thông báo cho trang web nơi bạn đã truy cập trước đó.</p>



<p class="wp-block-paragraph">Bạn hiểu đơn giản là trang web bạn truy cập trước khi request vào Web của họ.</p>



<p class="wp-block-paragraph"><strong>Giải pháp:</strong> Vì thế bạn nên đi từ Google vào nó sẽ làm bạn giống một người dùng thông thường hơn là Bot.</p>



<h3 id="4-web-scrape-slowly" class="wp-block-heading">4. <strong>Web Scrape Slowly</strong></h3>



<p class="wp-block-paragraph">Khi sử dụng các dịch vụ thu thập dữ liệu trên web, việc thu thập dữ liệu càng nhanh càng tốt. Tuy nhiên, một <em><strong>Real User</strong></em> ở lại một trang web, tốc độ duyệt web của họ khá chậm so với Bot của bạn. ( Con người cần phải suy nghĩ trước khi làm gì đó, còn bot thì không một vết xước =))))) )</p>



<p class="wp-block-paragraph">Ngoài ra, chủ sở hữu trang web thường có thể phát hiện người dọn dẹp của bạn bằng cách phân tích:</p>



<ul class="wp-block-list">
<li>Tốc độ cuộn trang của bạn.</li>



<li>Tần suất bạn nhấp và điều hướng trên các trang.</li>



<li>Nếu bạn tương tác với các trang quá nhanh, rất có thể trang web đó sẽ chặn bạn.</li>
</ul>



<p class="wp-block-paragraph"><strong>Giải pháp:</strong></p>



<ul class="wp-block-list">
<li>Random thời gian delay trong khi tương tác với nội dung JavaScript để mô phỏng hành vi của người dùng chuẩn.</li>



<li>Random thời gian giữa những Request</li>
</ul>



<h3 id="5-pursue-different-scraping-patterns" class="wp-block-heading">5. Pursue Different Scraping Patterns</h3>



<p class="wp-block-paragraph">Bạn nên kết hợp xen kẽ những action khác khi <strong>Scrape</strong> để tránh bị detect và chặn.</p>



<p class="wp-block-paragraph">Hiểu đơn giản là, người dùng thật không thể chỉ lặp đi lặp lại 1 chuỗi action cụ thể.</p>



<p class="wp-block-paragraph">Bad: Vào Login → Điền Username / Password → Vào trang cần lấy thông tin → <strong>Scrape</strong></p>



<p class="wp-block-paragraph">Good: Vào Login → Điền Username / Password → Vào trang cần lấy thông tin → Like / Xem Video → Scroll → <strong>Scrape</strong></p>



<h3 id="6-web-scrape-at-different-day-times" class="wp-block-heading">6. Web Scrape At Different Day Times</h3>



<p class="wp-block-paragraph">Bạn nên thực hiện <strong>Scrape</strong> vào nhiều khoảng thời gian cụ thể. Việc bạn request và thực hiện 1 hoạt động lặp đi lặp lại vào cùng 1 khoảng thời gian sẽ làm bạn bị nghi ngờ và gắn cờ.</p>



<h3 id="7-use-real-user-agents" class="wp-block-heading">7. Use Real User Agents</h3>



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



<p class="wp-block-paragraph"><strong>User Agents</strong> bao gồm một chuỗi duy nhất xác định thông tin trình duyệt đang được sử dụng, phiên bản của trình duyệt và hệ điều hành. Trình duyệt web User Agents cho trang web mỗi khi request được thực hiện.</p>



<p class="wp-block-paragraph">Cơ chớ chặn Scrape có thể phát hiện bot nếu bạn thực hiện một số lượng lớn yêu cầu từ một tác nhân người dùng. Cuối cùng, bạn sẽ bị chặn.</p>



<p class="wp-block-paragraph"><strong>Giải pháp:</strong> Để ngăn chặn tình trạng này, bạn nên có 1 build một danh sách <strong>User Agents</strong> có sẵn và <strong>override</strong> cho từng request vì không có trang web nào muốn chặn người dùng real.</p>



<h3 id="8-use-headless-browsers" class="wp-block-heading">8. <strong>Use Headless Browsers</strong></h3>



<p class="wp-block-paragraph">Một số trang web khó <strong>Scrape</strong> hơn. Chúng được thiết lập để phát hiện từ extension trình duyệt, phông chữ web đến cookie của trình duyệt để kiểm tra xem yêu cầu có đến từ người dùng thực hay không.</p>



<p class="wp-block-paragraph">Nếu bạn cần loại bỏ các trang web như vậy, bạn sẽ cần sử dụng trình duyệt không có giao diện người dùng. Các công cụ như Selenium và Puppeteer có nhiều tính năng như chụp ảnh màn hình tự động hoặc có thể nhấp vào các nút/thành phần nội dung tương tác.</p>



<h3 id="9-detect-website-changes" class="wp-block-heading">9. <strong>Detect Website Changes</strong></h3>



<p class="wp-block-paragraph">Thông thường chúng ta sẽ dựa vào DOM để <strong>Scrape</strong> lượng dữ liệu cần thiết.</p>



<p class="wp-block-paragraph">Các trang web thường có bố cục và chủ đề độc đáo của riêng chúng, điều này có thể khiến cho phần element của bạn bị lỗi khi chủ sở hữu trang web quyết định thiết kế lại bố cục. (thay đổi tên class, hoặc bất kì một thẻ nào mà bạn gắn cờ)</p>



<p class="wp-block-paragraph">Bạn sẽ cần phát hiện những thay đổi này bằng trình quét web của mình và tạo giải pháp giám sát liên tục để đảm bảo rằng trình thu thập dữ liệu web của bạn vẫn hoạt động. Một phương pháp là đếm số lượng yêu cầu thành công trên mỗi lần thu thập thông tin trên web.</p>



<p class="wp-block-paragraph">Ngoài ra, bạn có thể tạo các bài kiểm tra đơn vị cụ thể cho các loại bố cục khác nhau:</p>



<p class="wp-block-paragraph">Nếu có trang đánh giá hoặc trang sản phẩm thì bạn chỉ cần tạo UnitTest cho mọi loại bố cục trang. Sau đó, bạn sẽ chỉ cần gửi một số yêu cầu mỗi ngày để xem liệu bố cục có thay đổi hay không bằng việc liệu tất cả các UnitTest của bạn có thành công hay không.</p>



<h3 id="10-use-a-captcha-solving-service" class="wp-block-heading">10. <strong>Use a CAPTCHA Solving Service</strong></h3>



<p class="wp-block-paragraph">Bạn có thể rất cẩn thận và xây dựng Bot giống như 1 người dùng thật, tuy nhiên chủ dự án sử dụng CAPTCHA để kiểm duyệt <strong>Real User</strong> request thì sẽ không còn cách nào khác ngoài sử dụng dịch vụ để vượt qua.</p>



<p class="wp-block-paragraph"><strong>Giải pháp:</strong></p>



<ul class="wp-block-list">
<li><a href="https://anti-captcha.com/">Anti Captcha</a>.</li>



<li><a href="https://www.deathbycaptcha.com/">DeathByCaptcha</a>.</li>



<li><a href="https://2captcha.com/">2Captcha</a>.</li>
</ul>



<h3 id="phan-ket-luan" class="wp-block-heading"><strong>Phần kết luận</strong></h3>



<p class="wp-block-paragraph">Hy vọng rằng qua bài viết bạn đã học được một số kỹ thuật mới về cách giảm khả năng scrape web của bạn bị chặn.</p>



<p class="wp-block-paragraph">Nói chung, việc random IP của bạn và thêm <strong>Request Headers</strong> <strong>HTTP</strong> thực là quá đủ cho hầu hết các trường hợp sử dụng, tuy nhiên, đôi khi bạn sẽ phải sử dụng các <strong>Headless Browsers</strong> để lấy dữ liệu cần thiết.</p>
<p>The post <a href="https://blog.tomosia.com.vn/cac-nguyen-tac-tot-nhat-de-lay-du-lieu-tren-website-ma-khong-bi-chan/">Các nguyên tắc tốt nhất để lấy dữ liệu trên Website mà không bị chặn</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.tomosia.com.vn/cac-nguyen-tac-tot-nhat-de-lay-du-lieu-tren-website-ma-khong-bi-chan/feed/</wfw:commentRss>
			<slash:comments>9</slash:comments>
		
		
			</item>
	</channel>
</rss>
