Я рубин-юниор. Мое приложение позволяет пользователю вводить контакты и / или загружать файл CSV.
- Работая в моей локальной ветке, если я добавлю контакт - контакт будет добавлен из View, Controller и dBase, и там он отлично работает.
- Если я разрешаю пользователю импортировать файл CSV. Начнется импорт файла. Однако теперь пользователь не может добавить контакт через приложение. По сути, он зависает до завершения импорта CSV.
Я использую следующие версии:
ruby "2.3.0"
gem "rails", "4.2.5.1" gem "pg", "0.17.1" # postgresql database
gem "delayed_job_active_record", ">= 4.0.0.beta1" # background job
processing gem "delayed_job_web", ">= 1.2.0" # web interface for delayed job
Также использую:
> class CsvUploader < CarrierWave::Uploader::Base
def store_dir "uploads / # {model.class.to_s.underscore} / # {mount_as} / # {model.id}" end
Вот рабочий:
класс ImportCsvFileWorker
def self.perform (csv_file_id) csv_file = CsvFile.find (csv_file_id)
csv_file.import! csv_file.send_report! end
конец
Я использую службу синтаксического анализа smarecsv
def process_csv parser = :: ImportData :: SmartCsvParser.new (csv_file.file_url)
parser.each do |smart_row| csv_file.increment!(:total_parsed_records) begin self.contact = process_row(smart_row) rescue => e row_parse_error(smart_row, e) end end rescue => e # parser error or unexpected error csv_file.save_import_error(e) end
Блокирует ли delayed_job базу данных для пользователя / контакта, поэтому я не могу добавлять контакты через приложение?
Локально приложение заморожено / зависает или кажется заблокированным до тех пор, пока не будет завершена фоновая delayed_job (кстати, если я запускаю на Heroku, это вызывает ошибки H12, но, думаю, мне нужно сначала исправить проблему локально). Просто пытаюсь понять - что заставляет его блокироваться? Должен ли он делать это? Это код (бизнес-логика файла CSV и представление добавления контакта работают независимо)? Но сторона приложения не будет работать, если запущено фоновое задание или это способ обработки Active Record. Это можно обойти?
Я не изолировал его, но подозреваю, что если выполняется какое-либо фоновое задание, приложение становится недоступным.
Я попытался включить все относящиеся к делу факты - дайте мне знать, если потребуются какие-либо дополнительные подробности. большое спасибо за помощь.
ОБНОВЛЕНИЕ - я обнаружил, что у меня есть ContactMergingService, который, кажется, блокирует все контакты. Если я закомментирую эту услугу ниже, мое приложение не зависнет.
Итак, мой вопрос в том, какие есть другие варианты = Перед добавлением контакта я пытаюсь найти все существующие одинаковые адреса электронной почты (если я его найду, я добавляю контактные данные). как мне это сделать без блокировки базы данных?
это потому, что я использую метод поиска? Есть ли способ лучше?
> class ContactMergingService
>
> attr_reader :new_contact, :user
>
> def initialize(user, new_contact, _existing_records)
> @user = user
> @new_contact = new_contact
> @found_records = matching_emails_and_phone_numbers
> end
>
> def perform
> Rails.logger.info "[CSV.merging] Checking if new contact matches existing contact..."
> if (existing_contact = existing_contact())
> Rails.logger.info "[CSV.merging] Contact match found."
> merge(existing_contact, new_contact)
> existing_contact
> else
> Rails.logger.info "[CSV.merging] No contact match found."
> new_contact
> end end
>
> private
>
> def existing_contact
> Rails.logger.info "[CSV.merging] Found records: #{@found_records.inspect}"
> if @found_records.present?
> @user.contacts.find @found_records.first.owner_id # Fetch first owner
> end end
>
> def merge(existing_contact, new_contact)
> Rails.logger.info "[CSV.merging] Merging with existing contact (ID: #{existing_contact.id})..."
> merge_records(existing_contact, new_contact) end
>
> def merge_records(existing_relation, new_relation)
> existing_relation.attributes do |field, value|
> if value.blank? && new_relation[field].present?
> existing_relation[field] = new_relation[field]
> end
> end
> new_relation.email_addresses.each do |email_address|
> Rails.logger.info "[CSV.merging.emails] Email: #{email_address.inspect}"
> if existing_relation.email_addresses.find_by(email: email_address.email)
> Rails.logger.info "[CSV.merging.emails] Email address exists."
> else
> Rails.logger.info "[CSV.merging.emails] Email does not already exist. Saving..."
> email_address.owner = existing_relation
> email_address.save!
> end
> end
> new_relation.phone_numbers.each do |phone_number|
> Rails.logger.info "[CSV.merging.phone] Phone Number: #{phone_number.inspect}"
> if existing_relation.phone_numbers.find_by(number: phone_number.number)
> Rails.logger.info "[CSV.merging.phone] Phone number exists."
> else
> Rails.logger.info "[CSV.merging.phone] Phone Number does not already exist. Saving..."
> phone_number.owner = existing_relation
> phone_number.save!
> end
> end end
>
> def matching_emails_and_phone_numbers
> records = []
> if @user
> records << matching_emails
> records << matching_phone_numbers
> Rails.logger.info "[CSV.merging] merged records: #{records.inspect}"
> records.flatten!
> Rails.logger.info "[CSV.merging] flattened records: #{records.inspect}"
> records.compact!
> Rails.logger.info "[CSV.merging] compacted records: #{records.inspect}"
> end
> records end
>
> def matching_emails
> existing_emails = []
> new_contact_emails = @new_contact.email_addresses
> Rails.logger.info "[CSV.merging] new_contact_emails: #{new_contact_emails.inspect}"
> new_contact_emails.each do |email|
> Rails.logger.info "[CSV.merging] Checking for a match on email: #{email.inspect}..."
> if existing_email = @user.contact_email_addresses.find_by(email: email.email, primary: email.primary)
> Rails.logger.info "[CSV.merging] Found a matching email"
> existing_emails << existing_email
> else
> Rails.logger.info "[CSV.merging] No match found"
> false
> end
> end
> existing_emails end
>
> def matching_phone_numbers
> existing_phone_numbers = []
> @new_contact.phone_numbers.each do |phone_number|
> Rails.logger.info "[CSV.merging] Checking for a match on phone_number: #{phone_number.inspect}..."
> if existing_phone_number = @user.contact_phone_numbers.find_by(number: phone_number.number)
> Rails.logger.info "[CSV.merging] Found a matching phone number"
> existing_phone_numbers << existing_phone_number
> else
> Rails.logger.info "[CSV.merging] No match found"
> false
> end
> end
> existing_phone_numbers end
>
> def clean_phone_number(number)
> number.gsub(/[\s\-\(\)]+/, "") end
>
> end