在我的ruby on Rails应用程序上,当创建模型Deal时,我使用after_create在DealPrize表上创建奖品。

Deal和DealPrize有一个属于/有很多关系:一个Deal有很多Deal奖品,一个Dealprize属于Deal。

它的工作方式是这样的:在我的管理面板(使用activeadmin)上,在Deal中,我有一个“prize-number”列,并且我使用了after_create,这样,每次管理员创建新交易时,应用程序都会使用这个award_number列,并在DealPrize表中创建此数量的奖品(根据需要插入尽可能多的行)。

我使用rspec和FactoryGirl的测试失败。可能是由于rspec/factory girl在prepare_statements中的表现不佳。 我不确定。

这是我的代码

models/deal.rb

has_many :deal_prizes, dependent: :delete_all

after_create :create_dealprizes

# Constants
TIME_SET = Time.zone.now
CONNECTION = ActiveRecord::Base.connection.raw_connection

def create_dealprizes
  begin
    CONNECTION.describe_prepared('create_deal_prizes')
  rescue PG::InvalidSqlStatementName
    CONNECTION.prepare('create_deal_prizes', 'INSERT INTO deal_prizes (deal_id,created_at,updated_at,admin_user_id,prize_id) values ($1, $2, $3, $4, $5)')
  end

  Deal.transaction do
    self.prizes_number.times do |i|
      CONNECTION.exec_prepared('create_deal_prizes',  [
        { value: self.id},
        { value: TIME_SET },
        { value: TIME_SET },
        { value: self.admin_user_id },
        { value: 5 }
      ])
    end
  end
end

这是我的测试:我想确保在创建交易时,如果交易的awards_number为340,则将340行添加到应有的表Dealprizes上。
require 'spec_helper'

describe DealPrize do
  describe "the right number of rows are created inside DealPrize table when a Deal is created" do

    before do
      @initial_prize_count = DealPrize.count
      @deal_prize = FactoryGirl.create(:deal_prize)
      @deal       = FactoryGirl.create(:deal_prizes => [@deal_prize], :prizes_number => 277)
    end

    it "does create right nb of rows" do
      expect(DealPrize.count).to eq( @initial_prize_count + 277 )
    end
  end
end

我使用工厂进行交易:
FactoryGirl.define do
  factory :deal do
    country       "France"
    title         "Neque porro quisquam est qui dolorem"
    description   "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum"

    factory :deal_skips_validate do
      to_create {|instance| instance.save(validate: false) }
    end

  end
end

这是DealPrizes的工厂:
FactoryGirl.define do
  factory :deal_prize do
  end
end

这是我得到的错误:
PG::UnableToSend:
       server closed the connection unexpectedly
        This probably means the server terminated abnormally
        before or while processing the request.

如果需要,这是我如何处理spec_helper.rb中的事务
config.use_transactional_fixtures = false

config.before(:suite) do
  DatabaseCleaner.clean_with(:truncation, :except => %w(roles))
end

config.before(:each) do
  DatabaseCleaner.strategy = :transaction
end

config.before(:each, js: true) do
  DatabaseCleaner.strategy = :truncation
end

config.before(:each) do
  DatabaseCleaner.start
end

config.after(:each) do
  DatabaseCleaner.clean
end

最佳答案

每次方法运行时,您都需要从池中获取一个新的连接(并确保完成后将其返回到池中)。看一看with_connection

这样的事情应该起作用。

class Deal < ActiveRecord::Base
  has_many :deal_prizes, dependent: :delete_all

  after_create :create_dealprizes

  # Constants
  TIME_SET = Time.zone.now

  def create_dealprizes
    self.class.connection_pool.with_connection do |connection|
      begin
        connection.describe_prepared('create_deal_prizes')
      rescue PG::InvalidSqlStatementName
        connection.prepare('create_deal_prizes', 'INSERT INTO deal_prizes (deal_id,created_at,updated_at,admin_user_id,prize_id) values ($1, $2, $3, $4, $5)')
      end

      connection.execute("START TRANSACTION")
      prizes_number.times do |i|
        connection.exec_prepared('create_deal_prizes',  [
          { value: self.id},
          { value: TIME_SET },
          { value: TIME_SET },
          { value: self.admin_user_id },
          { value: 5 }
        ])
      end
      connection.execute("COMMIT")
    end
  end
end

这应该可行,但是我认为(就其值(value)而言)它不是非常像Ruby的。听起来您在担心性能,因此我将使用单个INSERT语句添加数据。您可以手动构建,但是activerecord-import gem使其非常容易。

使用该gem可能类似于:
class Deal < ActiveRecord::Base
  has_many :deal_prizes, dependent: :delete_all

  after_create :create_dealprizes

  def create_dealprizes
    prizes = prizes_number.times.map do
               deal_prizes.build(created_by: admin_user, prize_id: 5)
             end
    DealPrize.import(prizes)
  end
end

这是一个使用ActiveRecord导入的sample app

关于ruby-on-rails - rspec-PG::UnableToSend:服务器意外关闭了连接,这可能意味着服务器异常终止,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32638245/

10-13 04:44