2

Rails 3.1.3 アプリにはsubscriptionsテーブルがあります。このテーブルでの操作は追跡する必要があり、これは請求にとって重要です。データベースにはさまざまな方法 (API、コンソール、クライアント アプリ) でアクセスできるため、単純な ActiveRecord コールバックまたはオブザーバーでは、テーブル上のすべてのトランザクションが記録されていることを確認するのに十分ではありません。したがって、subscriptions何かが変更されるたびに「ログ」テーブルにレコードを挿入するテーブルにデータベーストリガーを作成します。そのために、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ます。ただし、アプリの作業を続け、subscriptionsRails 移行を使用してテーブルに列を追加する必要がありました。

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

移行を実行した後、トリガー機能を確認するテストは次のようになります。

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

失敗し始めました。

UPDATE : 開発データベースには、列を追加した後もまだトリガーがあります。テストデータベースは、列を追加する移行を実行した後にトリガーを失います...奇妙な

質問:
テーブルを変更するとトリガーが強制終了されますか? もしそうなら、トリガーが持続することを確認する方法は何ですか?

4

2 に答える 2

3

最後に、私はそれを理解しました。subscriptionsテーブルに列を追加した後、実行しましたrake db:test:prepare(理由は聞かないでください)。これは明らかに「現在のスキーマをダンプし、テスト データベースを吹き飛ばし、ダンプからテスト スキーマを再構築する」というものでした。SQL を実行することによってトリガーが作成されたため (レール ヘルパーではありません)、スキーマ ファイルに反映されることはありませんでした。したがって、ソリューションによって再作成されることはありませんでした。rake db:test:prepareテストデータベースを削除して、すべての移行を再度実行してください...そして二度と実行しないでrake db:test:prepareください。うまくいけば、誰かがそれが役に立つと思う.

于 2012-04-26T18:22:53.017 に答える
2

テーブルを変更するとトリガーが強制終了されますか?

尋ねられた質問に答えるには:いいえ、通常は違います。WHEN列を追加しても、トリガー関数内の SQL ステートメントまたはトリガーの条件(PostgreSQL 9.0 以降) に間接的に影響しない限り、トリガーをまったく混乱させるべきではありません。


テーブルを削除/再作成して列を追加する場合は、もちろん、トリガーも再作成する必要があります。トリガー関数はテーブルで削除されませんが、トリガーは削除されます。トリガーがまだ残っているか確認できますか?


ターゲット リストINSERTのないコマンドがあります。これは一般的なフットガンであり、基になるテーブルが後で変更されたときに破損する傾向があります。アドホック SQL コマンドを除き、常にターゲット リストを提供します。

それ以外の:

INSERT INTO subscription_log
SELECT OLD.company_id, OLD.product_id, OLD.package_id, ... ;

行う:

subscription_log に挿入(col1、col2、col3、...)
SELECT OLD.company_id, OLD.product_id, OLD.package_id, ... ;

マニュアルの INSERT に関する詳細。

于 2012-04-26T15:03:13.990 に答える