Пакетное обновление нескольких таблиц в Ruby On Rails

#ruby-on-rails #normalization #multiple-tables

#ruby-on-rails #нормализация #несколько таблиц

Вопрос:

Мне нужна некоторая помощь в продумывании процесса пакетного обновления нескольких таблиц для приложения RoR. Ниже приведены мои модели,

 class User < ActiveRecord::Base  
    has_many :addresses  
    has_many :phones  
end  


class Address < ActiveRecord::Base  
    belongs_to :user  
    has_one    :addresstype      
end  


class Phone < ActiveRecord::Base  
    belongs_to :user  
    has_one    :phonetype  
end  


class PhoneType < ActiveRecord::Base  
    belongs_to :phone  
end  


class AddressType < ActiveRecord::Base      
    belongs_to :address    
end    
  

Вы можете представить, что таблица «Address» имеет user_id, PhoneType имеет phone_id, а ADDRESSSTYPE имеет ключи address_id для поддержания ассоциаций.

Итак, я хочу обработать некоторые файлы с пользовательскими записями для вставки в соответствующие таблицы. Например,

 ...  
    usr1@foo.com,1234 sw main st. ca 19820,offce,425-378-1188,mobile  
    usr1@foo.com,7869 sw fool st. ca 19820,residential,425-898-2345,landline  
    usr2@foo.com,4321 sw oak st. ca 19822,offce,435-378-1298,mobile  
    usr3@foo.com,8789 sw adler st. ca 19822,residential,436-898-6234,landline  
...
  

миллионы из них либо все в одном файле, либо по одной записи на файл, переданный с удаленного сервера.

ИЛИ есть какой-либо другой способ обрабатывать эти удаленные запросы по требованию? Например, удаленные серверы отправляют запись в мое приложение RoR, и она обрабатывается через приложение RoR. В обоих случаях я хочу убедиться, что вставляемые данные проходят все правила проверки. Допустим, формат электронной почты или адрес не может быть пустым.

Эти записи могут быть в формате json для экономии объема данных, передаваемых в файле.

При обработке пользователем (usr1@foo.com ) может существовать, а может и не существовать.

Спасибо, и я действительно ценю любую помощь.

Atarang.

Ответ №1:

Вы можете сделать и то, и другое. Если у вас есть один файл, вы можете просто создать скрипт ruby и включить config/environment.rb для загрузки среды приложения rails в свой скрипт ruby. Затем вы можете загрузить файл и обработать каждую строку следующим образом:

 include 'config/environment.rb'
File.open("/folder/folder/file_to_parse", "r").each_line do |line| 
     .....
     # interpret line here
     ....
end
  

Если это в формате CSV, вы также можете использовать библиотеку rubys CSV(http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV.html )

С другой стороны, вы также могли бы создать интерфейс, который анализирует данные в JSON. Вы могли бы использовать реализацию JSON для ruby (которая документирована здесь:http://flori.github.com/json /) для создания действия, которое анализирует один объект, переданный в формате JSON.

//О проверках:

Напишите проверки в моделях! Затем вы проверяете все модели, которые belongs_to работают. потому что у вас, возможно, уже есть PhoneType , которые используются в фактической записи. Поэтому позаботьтесь о том, чтобы не получать дубликаты, когда они вам не нужны.

После этого вы используете new метод для создания новых объектов (не create потому что create выполняет запись в базу данных). Затем вы анализируете строку, и когда строка проанализирована, вы можете проверить все свои объекты, используя valid? метод, который проверяет, проходит ли объект все проверки, определенные в модели.

И только если все ваши объекты пройдут проверку, вы сохраняете их в базе данных. В противном случае вы просто не выполняете save метод, поэтому наборы данных, которые не передают проверки, не хранятся в базе данных.

//О выполнении

Если вам просто нужно выполнить импорт один раз, это не такая уж большая проблема, если скрипт не настолько совершенен. Что вы должны делать, когда в таблице много записей (100 — это не много, 100000 — это …), вы должны добавить индексы ко всем столбцам внешнего ключа. Вы можете создать миграцию addIndexesToForeignKeys и добавить индексы с помощью add_index метода, подобного этому:

 add_index :table_name, :column_name
  

Это ускорит запросы select и немного замедлит запросы insert, но я думаю, что show actions будут вызываться чаще, чем create actions 😉

Комментарии:

1. Davidb, спасибо за ваш ответ. Я буду читать больше о json. Но как насчет фактических вставок. Нужно ли мне выполнять следующее (последовательно)? Сначала проверьте пользователя и вставьте нового пользователя, если он не найден, затем получите user_id, получите phone_id для строки phonetype и address_id для строки addressstype. Затем вставьте запись адреса с идентификатором пользователя, addressstype_id и запись телефона с идентификатором пользователя, phonetype_id. Или есть способ получше?

2. Да, вы правы, проверки находятся в моделях. И .допустимо? метод может использоваться для проверок. Просто чтобы убедиться, что я правильно понял, поэтому, предполагая, что существуют типы телефона и адреса, в типичном случае будет 3 «метода ВЫБОРА или вызова .find()» сначала для user_id (используя строку адреса электронной почты), затем addressstype_id (используя строку типа адреса) и phonetype_id (используя строку типа телефона), и будет по крайней мере 2 новых объекта, адрес и телефон, которые нужно проверить и сохранить. Поток звучит нормально для меня. Верно? Это поднимает вопрос об эффективности или производительности сервера dbserver, обслуживающего все эти запросы.

3. Davidb, я попробую ваши предложения и обновлю этот thrread. Я действительно ценю ваше время. Спасибо.