从 Ruby on Rails 调用 PL/pgSQL 存储过程

Posted

技术标签:

【中文标题】从 Ruby on Rails 调用 PL/pgSQL 存储过程【英文标题】:Calling PL/pgSQL Stored Procedures from Ruby on Rails 【发布时间】:2013-06-15 02:52:27 【问题描述】:

我正在从事一个项目,我是 PostgreSQL 环境中的数据库设计师/管理员。领导决定使用 Rails 进行应用程序逻辑,并招聘了一名 Rails 程序员

Rails 程序员说,他通常编写所有应用程序代码,不喜欢有人向他传递存储过程所带来的缺乏控制,而且他从未在 Rails 中这样做过。

数据库使用了大量的继承/EERM,因此存储过程和触发器将使他的工作变得更加轻松,此外还可以从使用 procs 中获得性能优势。

我有四个问题:

1) 如何从 Rails 调用 pl/pgSQL 存储过程而没有返回值

2) 如何从 Rails 中调用具有单个返回值(1 行/1 列)的 pl/pgSQL 存储过程

3) 如何从 Rails 调用具有 1 行多列返回值的 pl/pgSQL 存储过程。

4) 如何使用 OUT 参数从 Rails 调用 pl/pgSQL 存储过程?

谢谢!

【问题讨论】:

除非你能说服你的 Rails 程序员使用像Sequel 这样的东西,否则你会度过一段糟糕的时光。默认的 Rails ORM (ActiveRecord) 不认为数据库应该包含任何逻辑,并且不理解比select * 和简单连接更复杂的任何东西,如果您违反约定使用“花哨”的东西,比如触发器、存储过程,甚至是准备好的语句。 是的...基于过程和继承的 DB + ActiveRecord 将引导您直接进入thedailywtf.com 领域。你必须接受使用 Rails 的决定(大概是它的 ActiveRecord ORM),然后把你的数据库设计扔到窗外,然后制作一个遵循 ActiveRecord 约定的设计(没有像“外键”或“约束”这样愚蠢的东西,反正谁想要它们?)。或者,改变决定,看看你是否可以让他们至少使用理智的 ORM。 【参考方案1】:

您好,我正在使用此代码来处理 PgSQL 存储过程 这涵盖了除了你最后一个问题之外的所有内容

   class SpActiveRecord < ActiveRecord::Base

      self.abstract_class = true
      #without return value
      def self.execute_sp(sql, *bindings)
        perform_sp(:execute, sql, *bindings)
      end
      #select many return values
      def self.fetch_sp(sql, *bindings)
        perform_sp(:select_all, sql, *bindings)
      end
      #select single return value
      def self.fetch_sp_val(sql, *bindings)
        perform_sp(:select_value, sql, *bindings)
      end

      protected
      def self.perform_sp(method, sql, *bindings)
        if bindings.any?
          sql = self.send(:sanitize_sql_array, bindings.unshift(sql))
        end
        self.connection.send(method, sql)
      end

    end

例子

class Invoice < SpActiveRecord

 def create_or_update
       raise ReadOnlyRecord if readonly? or !new_record?

        self.id = fetch_sp_val("SELECT * FROM billing.invoice_generate(?,?,?)", 
                               self.account_id,
                               self.start_date,
                               self.end_date)

       @new_record = false
       true
   end
end

【讨论】:

以上是关于从 Ruby on Rails 调用 PL/pgSQL 存储过程的主要内容,如果未能解决你的问题,请参考以下文章

Ruby on Rails:将数据调用到 javascript 中的首选方法?

Ruby on Rails 如何使用 yield 进行布局?

如何在 Ruby on Rails 的控制台中调用控制器/视图辅助方法?

ruby on rails 在关联调用中使用变量

Ruby on Rails 路由到控制器

对链接进行 ajax 调用单击以更新链接本身(Ruby on Rails)