如何使FactoryGirl.create影响另一个记录的属性? [英] How to make a FactoryGirl.create affect another record's attribute?

查看:71
本文介绍了如何使FactoryGirl.create影响另一个记录的属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在产品的 booking 后,通常在网店应用程序中, bookings_controller 创建操作会执行order.save,这反过来又会激活必要的before_save方法order.sum_of_all_bookings.

在为查看订单列表的管理员构建RSpec测试时,进行预订不会更改订单总数.索引确实可以在浏览器中工作.

 require 'rails_helper'

RSpec.feature 'Admin can oversee orders' do
  let(:admin) { FactoryGirl.create(:user, :admin) }
  let(:customer) { FactoryGirl.create( :user ) }
  let!(:order_1) { FactoryGirl.create( :order, customer: customer ) }
  let!(:booking_1) { FactoryGirl.create( :booking,  product_name: 'Honingpot', 
                                                    product_quantity: 1, 
                                                    product_price: '5,00', 
                                                    order: order_1 ) }
  let!(:order_2) { FactoryGirl.create( :order, customer: customer ) }
  let!(:booking_2) { FactoryGirl.create( :booking,  product_name: 'Streekpakket',
                                                    product_quantity: 2, 
                                                    product_price: '10,00', 
                                                    order: order_2 ) }


  before do
    order_1.sum_all_bookings
    order_2.sum_all_bookings
    login_as(admin)
    visit orders_path
  end

  scenario 'with success' do
    within('table#paid') do
      expect(page).to have_content '5,00'
      expect(page).to have_content '10,00'
    end
  end
end
 

Before块不起作用.

创建后的工厂女孩​​也不是:

 FactoryGirl.define do
  factory :booking do
    product_name 'Honingpot'
    product_quantity '1'
    product_price '3,99'
    order
    after(:create) { |booking| booking.order.save } # booking.order.sum_all_bookings, also not working
  end
end
 

RSpec打印订单中的预订,但订单总数不变.

如何使订单总和预订?

或更笼统地说:

如何使FactoryGirl.create影响另一个记录的属性?

解决方案

清理规范

首先,您的规格中有太多出厂配置. FactoryGirl 在此处用于根据您的规格将创建和设置移出. /p>

这不会直接解决您的问题,但是这些步骤将使您的测试过程更加干净,简单和快捷.

1.法克宝石

要开始进行修订,请继续添加 faker gem ,以便您轻松生成有用的,为您的工厂提供的随机数据.

FactoryGirl.define do
  factory :booking do
    product_name { Faker::Commerce.product_name }
    product_quantity { Faker::Number.number(2) }
    product_price Faker::Number.decimal(2)

    order
  end
end

去那里,准备好使用一些可靠的预订工厂.

2.性状

它们是使工厂适应特定情况的好方法.绝对在文档中详细了解它们.

FactoryGirl.define do
  factory :order do 
    customer

    trait :with_bookings do 
      after(:create) do |order|
        order.bookings << create_list(:booking, 2)
      end
    end
  end
end

现在,您可以轻松地创建带有或不带有预订的订单:

let(:order_with_bookings) { create(:order, :with_bookings) }

3.语法更简洁

您可以省略FactoryGirl语法,只需create(:order)即可.完成这些步骤后,您应该拥有一个更加干净的测试环境.

解决回调问题

据我了解,您可以这样设置回调:

class Order
  has_many :bookings

  before_save :update_order_cache

  def update_order_cache
    # calculation of the total bookings sum 
  end
end

class Booking
  belongs_to :order
end

但是您应该反过来做,在创建或更新产品之后,应该触发订单上的回调:

class Order
  has_many :bookings

  def update_order_cache
    # calculation of the total bookings sum 
  end
end

class Booking
  belongs_to :order

  after_save do
    order.update_order_cache
  end
end

如果该字段永远不能为空,还可以向该总和添加默认值.

validates :sum_field, presence: true, default: '0.0'

这应该为您总结一下.干杯!

In a webshop application normally after a booking of a product the bookings_controller create action does an order.save which in turn activates the necessary before_save method order.sum_of_all_bookings.

When building a RSpec test for an admin viewing a list of orders, making a booking doesn't change the total of an order. The indexing does work in the browser.

require 'rails_helper'

RSpec.feature 'Admin can oversee orders' do
  let(:admin) { FactoryGirl.create(:user, :admin) }
  let(:customer) { FactoryGirl.create( :user ) }
  let!(:order_1) { FactoryGirl.create( :order, customer: customer ) }
  let!(:booking_1) { FactoryGirl.create( :booking,  product_name: 'Honingpot', 
                                                    product_quantity: 1, 
                                                    product_price: '5,00', 
                                                    order: order_1 ) }
  let!(:order_2) { FactoryGirl.create( :order, customer: customer ) }
  let!(:booking_2) { FactoryGirl.create( :booking,  product_name: 'Streekpakket',
                                                    product_quantity: 2, 
                                                    product_price: '10,00', 
                                                    order: order_2 ) }


  before do
    order_1.sum_all_bookings
    order_2.sum_all_bookings
    login_as(admin)
    visit orders_path
  end

  scenario 'with success' do
    within('table#paid') do
      expect(page).to have_content '5,00'
      expect(page).to have_content '10,00'
    end
  end
end

Before block doesn't work.

Neither does the factory girl after create:

FactoryGirl.define do
  factory :booking do
    product_name 'Honingpot'
    product_quantity '1'
    product_price '3,99'
    order
    after(:create) { |booking| booking.order.save } # booking.order.sum_all_bookings, also not working
  end
end

RSpec prints the bookings being in the order, yet the order total being unchanged.

How to make the order sum the bookings?

Or more generally:

How to make a FactoryGirl.create affect another record's attribute?

解决方案

Cleaning up your specs

First off, you have too much factory configuration in your spec. FactoryGirl is here to move the creation and setup away from your specs.

This will not directly solve your problem, but these steps will make your testing proccess cleaner, simpler and faster.

1. Faker Gem

To get started with the revamp go ahead and add the faker gem so you can easily generate useful, random data for your factories.

FactoryGirl.define do
  factory :booking do
    product_name { Faker::Commerce.product_name }
    product_quantity { Faker::Number.number(2) }
    product_price Faker::Number.decimal(2)

    order
  end
end

There you go, some solid booking factories ready to be used.

2. Traits

They are a great way to adapt your factories for certain scenarios. Definitely read more about them in the docs.

FactoryGirl.define do
  factory :order do 
    customer

    trait :with_bookings do 
      after(:create) do |order|
        order.bookings << create_list(:booking, 2)
      end
    end
  end
end

So now you can easily create an order with or without bookings:

let(:order_with_bookings) { create(:order, :with_bookings) }

3. Cleaner syntax

You can leave out the FactoryGirl syntax, simply create(:order) will do. After these steps you should have a much cleaner test environment.

Solving the callback problem

As I understand it, you set up your callback like this:

class Order
  has_many :bookings

  before_save :update_order_cache

  def update_order_cache
    # calculation of the total bookings sum 
  end
end

class Booking
  belongs_to :order
end

But you should do it the other way round, after the product has been created or updated, the callback on the order should be triggered:

class Order
  has_many :bookings

  def update_order_cache
    # calculation of the total bookings sum 
  end
end

class Booking
  belongs_to :order

  after_save do
    order.update_order_cache
  end
end

You can also add a default value to the sum if that field should never be blank.

validates :sum_field, presence: true, default: '0.0'

This should wrap this up for you. Cheers!

这篇关于如何使FactoryGirl.create影响另一个记录的属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆