ruby-on-rails - 在 Rails 应用程序中更改 PostgreSQL 表会禁用触发器

标签 ruby-on-rails postgresql triggers rspec migration

在我的 Rails 3.1.3 应用程序中,我有 subscriptions 表;必须跟踪该表上的操作,这对于计费至关重要。由于可以通过多种方式访问​​数据库(API、控制台、客户端应用程序),因此简单的 ActiveRecord 回调或观察器不足以确保记录表上的所有事务。因此,我在 subscriptions 表上创建一个数据库触发器,只要发生变化,它就会在“log”表中插入一条记录。为了做到这一点,我使用 Rails 迁移,如下所示:

def up
   execute <<-SQL
     CREATE OR REPLACE FUNCTION FUNCTION_Event_Type() 
     RETURNS TRIGGER 
     AS 
     $TRIGGER_Event_Type$
      BEGIN
        IF (TG_OP = 'DELETE') THEN
              INSERT INTO subscription_log (company_id, product_id, old_package_id, new_package_id, trigger_type, updated_at, created_at)
               SELECT OLD.company_id, OLD.product_id, OLD.package_id, NULL, 'Delete', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP;
              RETURN OLD;
          ELSIF (TG_OP = 'UPDATE') THEN
              INSERT INTO subscription_log (company_id, product_id, old_package_id, new_package_id, trigger_type, updated_at, created_at) 
              SELECT OLD.company_id, OLD.product_id, OLD.package_id, NEW.package_id, 'Update', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP;
              RETURN NEW;
          ELSIF (TG_OP = 'INSERT') THEN
              INSERT INTO subscription_log (company_id, product_id, old_package_id, new_package_id, trigger_type, updated_at, created_at) 
              SELECT NEW.company_id, NEW.product_id, NULL, NEW.package_id, 'Insert', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP;
              RETURN NEW;
          END IF;
        RETURN NULL;
      END;
  $TRIGGER_Event_Type$ 
  LANGUAGE plpgsql;

  CREATE TRIGGER TRIGGER_Event_Type
  AFTER INSERT OR UPDATE OR DELETE ON subscriptions
      FOR EACH ROW EXECUTE PROCEDURE FUNCTION_Event_Type();
 SQL
end

触发器工作正常并根据需要记录。我有 rspec 测试,检查每当在 subscriptions 表上完成某些操作时,记录都会插入到“logging”表中。但是,我继续开发该应用程序,并且必须使用 Rails 迁移向 subscriptions 表添加一列:

def change
  add_column :subscriptions, :description, :text
end

运行迁移后,我的测试会检查触发器功能,如下所示:

  lambda do
    FactoryGirl.create(:subscription)
  end.should change(SubscriptionLog, :count).by(1)

开始失败。

更新:开发数据库在添加列后仍然有触发器。运行添加列的迁移后,测试数据库丢失触发器...奇怪

问题:
更改表会杀死触发器吗?如果确实如此,如何确保触发器持续存在?

最佳答案

我终于明白了。向 subscriptions 表添加一列后,我运行了 rake db:test:prepare (不要问我为什么)。显然,“转储当前模式,清除测试数据库,然后从转储中重建测试模式”由于触发器是通过执行 SQL(而不是 Rails 帮助程序)创建的,因此它从未反射(reflect)在模式文件中。因此,它从未被 rake db:test:prepare 重新创建 解决方案:删除测试数据库并再次运行所有迁移...并且永远不要运行 rake db:test:prepare > 再次。希望有人觉得它有用。

关于ruby-on-rails - 在 Rails 应用程序中更改 PostgreSQL 表会禁用触发器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10335263/

相关文章:

ruby-on-rails - STI 与 rails 中的多态关联

css - Rails 不包含使用 require_tree 和 scss 的样式

ruby-on-rails - Rails 3.2/4 : Is there a way to easily render a template (partial, 什么...)来自控制台?

arrays - 展平/连接聚合 JSONB 数组

mongodb - 选择一个数据库来存储 Report Json

WPF 在绑定(bind)失败时应用触发器

ruby-on-rails - Rails smart_listing 配置

node.js - "query values must be an array"...?

postgresql - 带有 INSTEAD OF 触发器的 Postgres INSERT ON CONFLICT 行为

mysql - AFTER INSERT 触发器在将数据插入初始表后将数据插入到不同的表中