добавление к rake db:seed в rails и запуск его без дублирования данных
-
28-09-2019 - |
Вопрос
Rake db: seed заполняет вашу базу данных значениями базы данных по умолчанию для приложения, верно?Ну и что, если у вас уже есть начальное значение, и вам нужно добавить к нему (вы добавляете новую функцию, для которой требуется начальное значение).По моему опыту, когда я снова запустил rake db: seed, он добавил уже существующий контент, так что существующий контент стал двойным.
Что мне нужно, так это добавить несколько семян, и при запуске он должен просто добавить самые новые и игнорировать существующие семена.Как мне с этим справиться?(грязный, нубовский способ, которым я обычно это делаю, - это усечь всю мою базу данных, а затем снова запустить seed, но это не очень разумно делать в продакшене, не так ли?)
Решение
Я делаю что-то вроде этого .... когда мне нужно добавить пользователя
В SEEDS.RB:
if User.count == 0
puts "Creating admin user"
User.create(:role=>:admin, :username=>'blagh', :etc=>:etc)
end
Вы можете стать более интересным, чем это, но в этом случае вы можете запустить его снова по мере необходимости.
Другие советы
Более чистый способ сделать это - использовать find_or_create_by
, следующим образом:
User.find_or_create_by_username_and_role(
:username => "admin",
:role => "admin",
:email => "me@gmail.com")
Вот возможные результаты:
- Существует запись с именем пользователя "admin" и ролью "admin".Эта запись НЕ будет обновляться новым сообщением электронной почты, если оно уже существует, но оно также НЕ будет удвоено.
- Запись с именем пользователя "admin" и ролью "admin" не существует.Будет создана приведенная выше запись.
- Обратите внимание, что если удовлетворен только один из критериев имени пользователя / роли, то будет создана вышеупомянутая запись.Используйте правильные критерии, чтобы убедиться, что вы не дублируете то, что хотите сохранить уникальным.
Еще один вариант, который может иметь небольшое преимущество в производительности:
# This example assumes that a role consists of just an id and a title.
roles = ['Admin', 'User', 'Other']
existing_roles = Role.all.map { |r| r.title }
roles.each do |role|
unless existing_roles.include?(role)
Role.create!(title: role)
end
end
Я думаю, что, делая это таким образом, вам нужно выполнить только один вызов базы данных, чтобы получить массив того, что существует, затем вам нужно вызвать еще раз, только если чего-то там нет и его нужно создать.
Мои предпочтения такого рода вещей - создать пользовательскую задачу грабли, а не использовать файл SEEDS.RB.
Если вы пытаетесь набрать создать пользователей, я создаю файлы .csv с данными, затем создайте задачу Rake, называемую Import_USERS и пропустите его имя файла. Затем петлю через его создать пользовательские записи.
В lib / tasks / import_users.rake:
namespace :my_app do
desc "Import Users from a .csv"
task :import_users => :environment do
# loop through records and create users
end
end
Затем беги так: rake bundle exec my_app:import_users path/to/.csv
Если вам нужно запустить его в производстве: RAILS_ENV=production bundle exec rake my_app:import_users /path/to/.csv
Добавление
от
departments = ["this", "that"]
departments.each{|d| Department.where(:name => d).first_or_create}
к
departments = ["this", "that", "there", "then"]
departments.each{|d| Department.where(:name => d).first_or_create}
Это простой пример,
Обновление / переименование
от
departments = ["this", "that", "there", "then"]
departments.each{|d| Department.where(:name => d).first_or_create}
к
departments = ["these", "those", "there", "then"]
new_names = [['these', 'this'],['those','that']]
new_names.each do |new|
Department.where(:name => new).group_by(&:name).each do |name, depts|
depts.first.update_column :name, new[0] if new[1] == name # skips validation
# depts[1..-1].each(&:destroy) if depts.size > 1 # paranoid mode
end
end
departments.each{|d| Department.where(:name => d).first_or_create}
ВАЖНЫЙ: Вам нужно обновить элементы departments
Массив еще дублирование обязательно произойдет.
Работать вокруг: Добавьте Validates_Uniquentainess_of Vavelation или проверка единственности, сравнивающих все необходимые атрибуты, но не используйте Методы пропускают проверки.
Действительно взломщик будет прокомментировать существующие данные, вот как я это сделал, и это работало нормально для меня
=begin
#Commented Out these lines since they where already seeded
PayType.create!(:name => "Net Banking")
PayType.create!(:name => "Coupouns Pay")
=end
#New data to be used by seeds
PayType.create!(:name => "Check")
PayType.create!(:name => "Credit card")
PayType.create!(:name => "Purchase order")
PayType.create!(:name => "Cash on delivery")
Однажды сделано, просто удалите комментарии
Еще одна тривиальная альтернатива:
#categories => name, color
categories = [
[ "Category 1", "#e51c23" ],
[ "Category 2", "#673ab7" ]
]
categories.each do |name, color|
if ( Category.where(:name => name).present? == false )
Category.create( name: name, color: color )
end
end
Просто добавь User.delete_all
И для всех моделей, которые вы включили в ваше приложение в начале вашего файла SEED.RB. Там не будет никаких дублирующих ценностей точно.