#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. Я действительно ценю ваше время. Спасибо.