【问题标题】:Is seeding data with fixtures dangerous in Ruby on Rails在 Ruby on Rails 中使用固定装置播种数据很危险
【发布时间】:2010-11-02 08:07:31
【问题描述】:

我有需要驻留在我的数据库(国家、地区、运营商等)中的初始数据的固定装置。我有一个任务 rake db:seed 将为数据库播种。

namespace :db do
  desc "Load seed fixtures (from db/fixtures) into the current environment's database." 
  task :seed => :environment do
    require 'active_record/fixtures'

    Dir.glob(RAILS_ROOT + '/db/fixtures/yamls/*.yml').each do |file|
      Fixtures.create_fixtures('db/fixtures/yamls', File.basename(file, '.*'))
    end
  end
end

我有点担心,因为这个任务会清除我的数据库并加载初始数据。事实上,这甚至可以在生产中不止一次地做,这让我吓坏了。这正常吗,我只需要小心吗?还是人们通常会以某种方式保护这样的任务?

【问题讨论】:

    标签: ruby-on-rails fixtures random-seed


    【解决方案1】:

    Rails 3 将使用 seed.rb 文件为您解决这个问题。

    http://github.com/brynary/rails/commit/4932f7b38f72104819022abca0c952ba6f9888cb

    【讨论】:

    • 会限制在数据库为空时加载吗?如果没有,为什么我仍然不能意外播种两次破坏实时数据?很高兴这终于成为惯例!
    • 您将使用 Ruby 代码填充它,就像您将种子数据写入迁移中一样。我的猜测是它只会执行你放入 seed.rb 文件的任何代码,所以它不会擦除数据库,而是添加到它(或更新,取决于你的代码)。
    • 希望它有一个“忽略重复条目”选项,这样我就可以在“追加”模式下播种两次并且没有重复数据......而且由于我处于“追加”模式,所以不用担心擦拭数据库干净
    【解决方案2】:

    在为数据库播种后,从生产服务器中删除任务怎么样?

    【讨论】:

    • 是的,这是一个很好的选择,但是我必须将其保留在存储库之外,否则每次部署时文件都会返回...或者我可以让 capistrano 在部署后删除文件...我认为这样更好。
    【解决方案3】:

    使用固定装置播种数据是一个非常糟糕的主意。

    Fixture 未经验证,并且由于大多数 Rails 开发人员不使用数据库约束,这意味着您可以轻松地将无效或不完整的数据插入到生产数据库中。

    默认情况下,Fixtures 还设置了奇怪的主键 ID,这不一定是问题,但使用起来很烦人。

    对此有很多解决方案。我个人最喜欢的是运行 Ruby 脚本的 rake 任务,该脚本仅使用 ActiveRecord 插入记录。这就是 Rails 3 对 db:seed 所做的事情,但您可以自己轻松编写。

    我用我添加到 ActiveRecord::Base 的方法来补充它,称为create_or_update。使用它我可以多次运行种子脚本,更新旧记录而不是抛出异常。

    不久前我写了一篇关于这些技术的文章,名为Loading seed data

    【讨论】:

    • 我绝对喜欢通过活动记录来做,但我认为你不能那样设置主键。我得试一试你文章中的方法。
    • 如果您播种的数据没有与之关联的模型怎么办?
    • 如果它没有模型,是否意味着您没有将数据存储在数据库中?在那种情况下,我会使用常量。您可以在初始化程序中设置它们。
    • 我不能接受你的论点。我还是喜欢固定装置。而且比你的方法快很多!
    【解决方案4】:

    对于您问题的第一部分,是的,我只是为在生产中运行这样的任务采取了一些预防措施。我在引导/播种任务中设置了这样的保护:

    task :exit_or_continue_in_production? do
      if Rails.env.production?
        puts "!!!WARNING!!! This task will DESTROY " +
             "your production database and RESET all " +
             "application settings"
        puts "Continue? y/n"
        continue = STDIN.gets.chomp
        unless continue == 'y'
          puts "Exiting..."
          exit! 
        end
      end
    end
    

    我为某些上下文创建了this gist

    对于问题的第二部分——通常你真的想要两件事:a)很容易为数据库播种并设置应用程序以进行开发,b)在生产服务器上引导应用程序(例如:插入管理员用户,创建文件夹应用程序依赖等)。

    我会在开发中使用固定装置进行播种——然后团队中的每个人都会在应用程序中看到相同的数据,并且应用程序中的内容与测试中的内容一致。 (通常我将 rake app:bootstraprake app:seed rake gems:install 等包装到 rake app:install 中,这样每个人都可以通过克隆 repo 并运行这个任务来处理应用程序。)

    但是,我绝不会在生产服务器上使用固定装置进行播种/引导。 Rails 的db/seed.rb 非常适合此任务,但您当然可以将相同的逻辑放入您自己的rake app:seed 任务中,就像其他人指出的那样。

    【讨论】:

      【解决方案5】:

      我刚刚有了一个有趣的想法……

      如果您创建了 \db\seeds\ 并添加了迁移样式的文件会怎样:

      文件:200907301234_add_us_states.rb

      class AddUsStates < ActiveRecord::Seeds
      
        def up
          add_to(:states, [
            {:name => 'Wisconsin', :abbreviation => 'WI', :flower => 'someflower'},
            {:name => 'Louisiana', :abbreviation => 'LA', :flower => 'cypress tree'}
            ]
          end
        end
      
        def down
          remove_from(:states).based_on(:name).with_values('Wisconsin', 'Louisiana', ...)
        end
      end
      

      或者:

        def up
          State.create!( :name => ... )
        end
      

      这将允许您以允许它们更和平共存的顺序运行迁移和种子。

      想法?

      【讨论】:

        【解决方案6】:

        我们已经建立了一系列用于播种数据的最佳做法。我们严重依赖播种,并且我们有一些独特的要求,因为我们需要播种多租户系统。以下是我们使用的一些最佳做法:

        1. Fixtures 不是最好的解决方案,但您仍然应该将种子数据存储在 Ruby 以外的其他地方。用于存储种子数据的 Ruby 代码往往会重复,将数据存储在可解析的文件中意味着您可以编写通用代码以一致的方式处理种子。
        2. 如果您打算更新种子,请使用名为 code 的标记列将种子文件与实际数据相匹配。永远不要依赖 id 在环境之间保持一致。
        3. 考虑如何处理更新现有种子数据。用户是否有可能修改了这些数据?如果是这样,您是否应该维护用户的信息而不是用种子数据覆盖它?

        如果您对我们播种的某些方式感兴趣,我们已将它们打包到名为 SeedOMatic 的 gem 中。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-10-14
          • 2010-10-20
          • 2016-04-30
          • 1970-01-01
          • 2015-05-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多