Fix e-paper subscriber import getting stuck on duplicate emails
This commit is contained in:
parent
f4cf48409e
commit
3b8317e6c0
|
|
@ -106,20 +106,42 @@ class Admin::EPaperSubscribersController < OrbitAdminController
|
|||
:status=>'Importing',
|
||||
'all_count'=>all_count,
|
||||
'current_count'=>current_count,
|
||||
'finish_percent'=>finish_percent
|
||||
'finish_percent'=>finish_percent,
|
||||
'pid'=>Process.pid
|
||||
}
|
||||
)
|
||||
|
||||
# 修改點:迴圈外先準備一個陣列,收集匯入失敗的列,最後要回報給使用者
|
||||
failed_rows = []
|
||||
existing_subscribers = {}
|
||||
EPaperSubscriber.all.each { |s| existing_subscribers[s.email] = s }
|
||||
|
||||
if subscribe_sheet
|
||||
subscribe_sheet.each_with_index do |row, i|
|
||||
next if i < 1
|
||||
next if row.nil?
|
||||
email = row.cells[0]&.value
|
||||
next if email.blank?
|
||||
|
||||
subscriber = EPaperSubscriber.where(:email=>email).first || EPaperSubscriber.new(:email=>email)
|
||||
subscriber.subscribed = true
|
||||
subscriber.language = row.cells[1]&.value.presence || I18n.locale.to_s
|
||||
subscriber.save
|
||||
# 修改點:查詢前先用跟 model 一樣的清洗規則處理 email,避免「查詢用原始字串、儲存用清洗後字串」不一致造成誤判成新資料
|
||||
fixed_email = email.to_s.gsub(/[ ]/,'').sub(/;$/, '').downcase
|
||||
|
||||
if fixed_email.count('@') > 1
|
||||
failed_rows << { row: i + 1, email: email.to_s, reason: '一個欄位包含多個信箱,請拆成單獨一列後重新匯入' }
|
||||
current_count += 1
|
||||
next
|
||||
end
|
||||
begin
|
||||
# 修改點:改用記憶體 Hash 查詢,取代資料庫查詢
|
||||
subscriber = existing_subscribers[fixed_email] || EPaperSubscriber.new(:email=>fixed_email)
|
||||
subscriber.subscribed = true
|
||||
subscriber.language = row.cells[1]&.value.presence || I18n.locale.to_s
|
||||
subscriber.save!
|
||||
# 修改點:存檔成功後更新 Hash,避免同一份檔案裡後面重複出現的同一個email又找不到
|
||||
existing_subscribers[subscriber.email] = subscriber
|
||||
rescue => e
|
||||
failed_rows << { row: i + 1, email: email.to_s, reason: e.message }
|
||||
end
|
||||
|
||||
current_count += 1
|
||||
if current_count % puts_every_count == 0
|
||||
|
|
@ -132,13 +154,32 @@ class Admin::EPaperSubscribersController < OrbitAdminController
|
|||
if unsubscribe_sheet
|
||||
unsubscribe_sheet.each_with_index do |row, i|
|
||||
next if i < 1
|
||||
# 修改點:對齊Subscribe那段,整列空白時row本身是nil,要先擋掉
|
||||
next if row.nil?
|
||||
email = row.cells[0]&.value
|
||||
next if email.blank?
|
||||
|
||||
subscriber = EPaperSubscriber.where(:email=>email).first || EPaperSubscriber.new(:email=>email)
|
||||
subscriber.subscribed = false
|
||||
subscriber.language = row.cells[1]&.value.presence || I18n.locale.to_s
|
||||
subscriber.save
|
||||
# 修改點:對齊Subscribe那段,查詢前先用同一套清洗規則處理email
|
||||
fixed_email = email.to_s.gsub(/[ ]/,'').sub(/;$/, '').downcase
|
||||
|
||||
# 修改點:對齊Subscribe那段,擋下一格塞多個信箱的資料
|
||||
if fixed_email.count('@') > 1
|
||||
failed_rows << { row: i + 1, email: email.to_s, reason: '一個欄位包含多個信箱,請拆成單獨一列後重新匯入' }
|
||||
current_count += 1
|
||||
next
|
||||
end
|
||||
|
||||
# 修改點:對齊Subscribe那段,改用記憶體Hash查詢取代資料庫查詢
|
||||
# 修改點:save改save!並包begin/rescue,例外不再讓整條Thread死掉
|
||||
begin
|
||||
subscriber = existing_subscribers[fixed_email] || EPaperSubscriber.new(:email=>fixed_email)
|
||||
subscriber.subscribed = false
|
||||
subscriber.language = row.cells[1]&.value.presence || I18n.locale.to_s
|
||||
subscriber.save!
|
||||
existing_subscribers[subscriber.email] = subscriber
|
||||
rescue => e
|
||||
failed_rows << { row: i + 1, email: email.to_s, reason: e.message }
|
||||
end
|
||||
|
||||
current_count += 1
|
||||
if current_count % puts_every_count == 0
|
||||
|
|
@ -153,7 +194,8 @@ class Admin::EPaperSubscribersController < OrbitAdminController
|
|||
:status=>'finish',
|
||||
'all_count'=>all_count,
|
||||
'current_count'=>current_count,
|
||||
'finish_percent'=>100
|
||||
'finish_percent'=>100,
|
||||
'failed_rows'=>failed_rows
|
||||
}
|
||||
)
|
||||
end
|
||||
|
|
@ -161,6 +203,19 @@ class Admin::EPaperSubscribersController < OrbitAdminController
|
|||
redirect_to admin_e_paper_subscribers_path(thread_id: thread.id)
|
||||
end
|
||||
|
||||
def last_import_result
|
||||
thread = Multithread.where(:key=>'import_epaper_subscribers').first
|
||||
stalled = false
|
||||
if thread && thread.status['status'] == 'Importing' && thread.status['pid']
|
||||
begin
|
||||
Process.kill(0, thread.status['pid'])
|
||||
rescue Errno::ESRCH
|
||||
stalled = true
|
||||
end
|
||||
end
|
||||
render :partial => 'last_import_result', locals: { thread: thread, stalled: stalled }
|
||||
end
|
||||
|
||||
def download_excel_format
|
||||
@subscribers = []
|
||||
@unsubscribers = []
|
||||
|
|
|
|||
|
|
@ -7,14 +7,19 @@ class EPaperSubscriber
|
|||
field :subscribed, type: Boolean, :default => true
|
||||
field :language
|
||||
field :last_paper_sent
|
||||
|
||||
before_save do
|
||||
self.fix_email
|
||||
if self.class.where(:email=>self.email, :language=>self.language,:subscribed=>true).count != 0
|
||||
return false
|
||||
# 修改點:用 throw(:abort) 取代 return false(Rails 5+ block 內不可用 return)
|
||||
# 修改點:排除自己這筆(self.id.ne=>self.id),避免更新既有紀錄時把自己算成重複
|
||||
if self.class.where(:id.ne=>self.id, :email=>self.email, :language=>self.language, :subscribed=>true).count != 0
|
||||
throw(:abort)
|
||||
end
|
||||
end
|
||||
|
||||
def fix_email(save_flag=false)
|
||||
self.email = self.email.to_s.gsub(/[ ]/,'').sub(/;$/, '')
|
||||
# 修改點:加上 .downcase,統一大小寫,避免 ABC@Gmail.com 跟 abc@gmail.com 被當成兩筆
|
||||
self.email = self.email.to_s.gsub(/[ ]/,'').sub(/;$/, '').downcase
|
||||
self.save if save_flag
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -53,9 +53,7 @@
|
|||
content_tag(:div, link_to(t("e_paper.export"), admin_e_paper_subscribers_export_excel_path + '.xlsx', :class=>"btn btn-success"), class: "pull-right")
|
||||
%>
|
||||
<div class="dropup upload-button pull-right">
|
||||
<% if @thread %>
|
||||
<button class="show_progress btn btn-primary" type="button"><%= t("e_paper.show_progress") %></button>
|
||||
<% end %>
|
||||
<button class="btn btn-default" id="show-last-import-result" type="button">查看最近一次匯入</button>
|
||||
<button class="btn btn-info dropdown-toggle" type="button" data-toggle="dropdown">
|
||||
<i class="icon-upload-alt icon-white"></i><%= t('personal_journal.upload') %>
|
||||
<span class="caret"></span>
|
||||
|
|
@ -94,7 +92,20 @@
|
|||
window.clearTimeout(window.time_out_id);
|
||||
window.setTimeout(function(){
|
||||
$("#threadModal").modal("hide");
|
||||
alert(data["status"]);
|
||||
// 修改點:is_finish後檢查failed_rows,有內容才組成清單提醒,取代原本單純alert(status)
|
||||
var failed_rows = data["failed_rows"];
|
||||
if(failed_rows && failed_rows.length > 0){
|
||||
var msg = "匯入完成,但有 " + failed_rows.length + " 筆資料匯入失敗:\n\n";
|
||||
failed_rows.slice(0, 20).forEach(function(r){
|
||||
msg += "第" + r["row"] + "列 (" + r["email"] + "):" + r["reason"] + "\n";
|
||||
});
|
||||
if(failed_rows.length > 20){
|
||||
msg += "\n...等共 " + failed_rows.length + " 筆,僅顯示前20筆";
|
||||
}
|
||||
alert(msg);
|
||||
}else{
|
||||
alert(data["status"]);
|
||||
}
|
||||
}, 3000);
|
||||
return;
|
||||
}
|
||||
|
|
@ -107,10 +118,15 @@
|
|||
$("#threadModal").on('shown.bs.modal',function(){
|
||||
window.time_out_id = window.setTimeout(update_thread, 1000);
|
||||
})
|
||||
$("#threadModal").modal("show");
|
||||
$(".show_progress").click(function(){
|
||||
$("#threadModal").modal("show");
|
||||
})
|
||||
}
|
||||
$("#show-last-import-result").click(function(){
|
||||
$.get("<%=admin_e_paper_subscribers_last_import_result_path%>", function(html){
|
||||
if($("#lastImportResultModal").length == 0){
|
||||
$("body").append('<div id="lastImportResultModal" class="modal hide fade" tabindex="-1"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><h3>上次匯入結果</h3></div><div id="lastImportResultBody"></div><div class="modal-footer"><button class="btn" data-dismiss="modal">關閉</button></div></div></div></div>');
|
||||
}
|
||||
$("#lastImportResultBody").html(html);
|
||||
$("#lastImportResultModal").modal("show");
|
||||
});
|
||||
});
|
||||
})
|
||||
</script>
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
<div class="modal-body">
|
||||
<p style="color:#888;font-size:0.9em;">此畫面顯示的是查詢當下的狀態,若匯入仍在進行中,請關閉後重新點擊按鈕以取得最新進度。</p>
|
||||
|
||||
<% if thread.nil? %>
|
||||
<p>目前沒有匯入紀錄。</p>
|
||||
<% elsif stalled %>
|
||||
<p style="color:#c00;font-weight:bold;">匯入似乎已意外中斷(原本處理這次匯入的伺服器程序已經不存在,可能是伺服器重啟或未預期的錯誤所致)。</p>
|
||||
<p>中斷前已處理:<%= thread.status['current_count'] %> / <%= thread.status['all_count'] %>(<%= thread.status['finish_percent'] %>%),這些資料已寫入資料庫,不會消失。如需完成剩餘資料,請重新上傳檔案。</p>
|
||||
<% else %>
|
||||
<p>狀態:<%= thread.status['status'] %>/已處理 <%= thread.status['current_count'] %> / <%= thread.status['all_count'] %>(<%= thread.status['finish_percent'] %>%)</p>
|
||||
<% end %>
|
||||
|
||||
<% if thread %>
|
||||
<% failed_rows = thread.status['failed_rows'] || [] %>
|
||||
<% if failed_rows.empty? %>
|
||||
<p>沒有失敗紀錄。</p>
|
||||
<% else %>
|
||||
<p>共 <%= failed_rows.count %> 筆匯入失敗:</p>
|
||||
<table class="table">
|
||||
<thead><tr><th>列號</th><th>Email</th><th>原因</th></tr></thead>
|
||||
<tbody>
|
||||
<% failed_rows.each do |r| %>
|
||||
<tr>
|
||||
<td><%= r['row'] %></td>
|
||||
<td><%= r['email'] %></td>
|
||||
<td><%= r['reason'] %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
@ -33,6 +33,7 @@ Rails.application.routes.draw do
|
|||
get 'e_paper_subscribers/export_excel', to: 'e_paper_subscribers#export_excel'
|
||||
get 'e_paper_subscribers/download_excel_format', to: 'e_paper_subscribers#download_excel_format'
|
||||
post 'e_paper_subscribers/import_from_excel', to: 'e_paper_subscribers#import_from_excel'
|
||||
get 'e_paper_subscribers/last_import_result', to: 'e_paper_subscribers#last_import_result'
|
||||
get 'e_paper_subscribers/get_subscribers_modal', to: 'e_paper_subscribers#get_subscribers_modal'
|
||||
get 'e_paper_subscribers/batch_delete_subscribers', to: 'e_paper_subscribers#batch_delete_subscribers'
|
||||
post 'e_paper_subscribers/delete_subscribers', to: 'e_paper_subscribers#delete_subscribers'
|
||||
|
|
|
|||
Loading…
Reference in New Issue