Rails,PostgreSQL和历史触发器

Lan*_*ane 1 ruby database postgresql triggers ruby-on-rails

所以...

我正在通过类似的东西添加由触发器填充的历史表,以便在我的项目中进行审计.

execute <<-SQL
  CREATE OR REPLACE FUNCTION process_history_table() RETURNS TRIGGER AS $history_table$
    BEGIN
      IF (TG_OP = 'DELETE') THEN
          INSERT INTO history_table VALUES (DEFAULT, 'D', now(), OLD.*);
          RETURN OLD;
      ELSIF (TG_OP = 'UPDATE') THEN
          INSERT INTO history_table VALUES (DEFAULT, 'U', now(), NEW.*);
          RETURN NEW;
      ELSIF (TG_OP = 'INSERT') THEN
          INSERT INTO history_table VALUES (DEFAULT, 'I', now(), NEW.*);
          RETURN NEW;
      END IF;
      RETURN NULL; -- result is ignored since this is an AFTER trigger
    END;
  $history_table$ LANGUAGE plpgsql;

  CREATE TRIGGER history_table
  AFTER INSERT OR UPDATE OR DELETE ON table
    FOR EACH ROW EXECUTE PROCEDURE process_history_table();
SQL
Run Code Online (Sandbox Code Playgroud)

......这将适用于生产和其他环境.问题是当某人运行bundle exec rake db:drop db:create db:schema:load db:migrate RAILS_ENV=test或类似的东西(最重要的是db:schema:load部分)时,这将绕过触发器创建,因为触发器未保存在db/schema.rb文件中.

也许正确的解决方案是,在使用rails时,开发人员不应该运行db:schema:load并始终运行,db:migrate以确保可以连续重新运行所有迁移.但是,我们很长一段时间没有这样做,我相信这样做会非常痛苦,因为我们可能需要更新几十个或更多的迁移.关于如何将触发器逐步合并到我的应用程序中以及继续以与今天相同的方式构建/重新创建开发人员/测试环境的任何想法将非常有帮助.

谢谢!

mu *_*ort 5

如果您需要或想要ActiveRecord不理解的特定于数据库的功能,那么您应该切换到db/structure.sql跟踪架构.db/structure.sql几乎是使用数据库的本机工具制作的模式的原始转储,因此它将包含触发器,CHECK约束,函数结果索引以及其他所有内容.

切换很简单:

  1. 更新您config/application.rb的包含config.active_record.schema_format = :sql.
  2. 做一个rake db:structure:dump初始的db/structure.sql.
  3. db/schema.rb从目录树和修订控件中删除.
  4. 添加db/structure.sql到修订控件.
  5. 调整你的佣金习惯:
    • db:structure:dump而不是db:schema:dump
    • db:structure:load而不是db:schema:load

其他一切都应该像往常一样工作(当然,假设你是理智的,并使用PostgreSQL进行开发,测试和生产).

通过此更改,将跟踪您的触发器db/structure.sql并重新创建数据库不会丢失它们.