附加到 rake db:seed in rails 并在不复制数据的情况下运行它
Posted
技术标签:
【中文标题】附加到 rake db:seed in rails 并在不复制数据的情况下运行它【英文标题】:appending to rake db:seed in rails and running it without duplicating data 【发布时间】:2011-03-29 11:10:42 【问题描述】:Rake db:seed 使用应用程序的默认数据库值填充您的数据库,对吗?那么如果你已经有一个种子并且你需要添加它(你添加一个需要种子的新功能)。根据我的经验,当我再次运行 rake db:seed 时,它已经添加了现有内容,因此现有内容变成了两倍。
我需要添加一些种子,在运行时,它应该只添加最新的种子,而忽略现有的种子。我该怎么做? (我通常做的肮脏的菜鸟方式是截断我的整个数据库然后再次运行种子,但这在生产中不是很聪明,对吧?)
【问题讨论】:
【参考方案1】:更简洁的方法是使用find_or_create_by
,如下所示:
User.find_or_create_by_username_and_role(
:username => "admin",
:role => "admin",
:email => "me@gmail.com")
以下是可能的结果:
-
存在用户名“admin”和角色“admin”的记录。如果该记录已存在,则不会使用新电子邮件更新此记录,但也不会加倍。
用户名“admin”和角色“admin”的记录不存在。将创建上述记录。
请注意,如果仅满足用户名/角色标准之一,它将创建上述记录。使用正确的标准来确保您不会重复您想要保持独特性的内容。
【讨论】:
1.是错的。那里的任何属性都不会更新。如果要更新记录,则需要进行后续更新。顾名思义,它将查找或创建,而不是查找或更新。 @BillLeeper - 你完全正确。感谢您纠正我的假设 - 我刚刚更新了答案。 没问题,我相信很多人也有过这样的经历。不知道为什么没有标准的 find_create_or_update,但是有很多不同方法的例子。【参考方案2】:我做这样的事情......当我需要添加用户时
在种子.rb 中:
if User.count == 0
puts "Creating admin user"
User.create(:role=>:admin, :username=>'blagh', :etc=>:etc)
end
您可以获得比这更有趣的东西,但在这种情况下,您可以根据需要再次运行它。
【讨论】:
hmmm 所以我基本上可以将 count == 0 添加到我需要在种子中填充的任何表中,以确保它们不会重复对吗?谢谢!我也在考虑为此做一个 rake 任务 您可能还必须在创建特定记录之前找到它们。检查他们的存在:例如User.create(:name => "Bob") unless User.find_by_name("Bob")
【参考方案3】:
另一个可能对性能有轻微好处的选项:
# 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
我认为这样做,您只需执行一次 db 调用即可获取存在的数组,然后如果某些内容不存在且需要创建,则只需再次调用。
【讨论】:
existing_roles = Role.all.map |r| r.title 可以写成 Role.all.collect(&:title),或者在 Rails 3.2 中只是 Role.pluck(:title) 也可以(roles - existing_roles).each |role| Role.create! title: role
【参考方案4】:
添加
来自
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_uniqueness_of 验证或比较所有必要属性的唯一性验证,但不要使用 methods skipping validations。
【讨论】:
【参考方案5】:我对这类事情的偏好是创建自定义 rake 任务,而不是使用 seed.rb 文件。
如果您尝试批量创建用户,我会使用数据创建一个 .csv 文件,然后创建一个名为 import_users 的 rake 任务并将文件名传递给它。然后遍历它以创建用户记录。
在 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
【讨论】:
【参考方案6】:一种真正可行的方法是注释掉现有数据,我就是这样做的,它对我来说很好用
=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")
完成后只需删除 cmets
【讨论】:
【参考方案7】:另一个简单的选择:
#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
【讨论】:
【参考方案8】:只需在 seed.rb 文件的开头添加User.delete_all
和您在应用程序中包含的所有模型。肯定不会有任何重复的值。
【讨论】:
您误解了这个问题。 OP 明确提到他想在生产中执行此操作,并且截断数据库是有风险的。您的回答忽略了部分问题。我建议你删除它。 这既有性能问题,也有数据风险 - 如果任何种子数据曾经更新过或曾经受到任何其他迁移的影响,删除所有内容并尝试重置不一定会恢复您的数据想要。以上是关于附加到 rake db:seed in rails 并在不复制数据的情况下运行它的主要内容,如果未能解决你的问题,请参考以下文章
在 AWS Elastic Beanstalk 上运行 rake db:seed
如何在亚马逊 opswork 中运行 rake db:seed