RailsでPostgreSQLのストアードプロシージャの例外コードを受ける
PostgreSQLのストアードプロシージャで例外を出した時に、素のままではRailsではエラーコードが受け取れません。
RailsというかRubyのpgというドライバーがデフォルトでは受け取らないようになっています。
pgを直接扱っている場合には、簡単に設定できるのですがRailsでは一苦労いります。
initializersにドライバーと例外に手を入れるコードを書きます。
vi config/initializers/stored_procedure.rb
使い方は以下の通り。
例外eはActiveRecord::StatementInvalidのインスタンスでoriginal_exceptionに本当の例外PG::ServerErrorを持っています。
PG::ServerErrorはPG::Resultのインスタンスresultを持っていて、ここのエラーコードが含まれています。
エラーメッセージは以下の通りです。
アプリケーションとしてはエラーコードだけ欲しいので、PG::Resultに手を入れて
error_codeでメッセージだけを取るようにメソッドを追加しています。
RailsというかRubyのpgというドライバーがデフォルトでは受け取らないようになっています。
pgを直接扱っている場合には、簡単に設定できるのですがRailsでは一苦労いります。
initializersにドライバーと例外に手を入れるコードを書きます。
vi config/initializers/stored_procedure.rb
require 'active_record/connection_adapters/postgresql_adapter'
module ActiveRecord
module ConnectionAdapters
class PostgreSQLAdapter
alias :base_configure_connection :configure_connection
def configure_connection
base_configure_connection
@connection.set_error_verbosity(PG::PQERRORS_VERBOSE)
end
end
end
end
module PG
class Result
def error_code
error_message[8..12]
end
end
end
使い方は以下の通り。
def index
begin
TestModel.find_by_sql(["SELECT * FROM test_get_list_data(p_id := :id", {id: 1}])
rescue => e
Rails.logger.debug(e.original_exception.result.error_code)
Rails.logger.debug(e.original_exception.result.error_message)
end
end
例外eはActiveRecord::StatementInvalidのインスタンスでoriginal_exceptionに本当の例外PG::ServerErrorを持っています。
PG::ServerErrorはPG::Resultのインスタンスresultを持っていて、ここのエラーコードが含まれています。
エラーメッセージは以下の通りです。
ERROR: U0001: error occerd p_id=1
LOCATION: exec_stmt_raise, pl_exec.c:3068
アプリケーションとしてはエラーコードだけ欲しいので、PG::Resultに手を入れて
error_codeでメッセージだけを取るようにメソッドを追加しています。