【问题标题】:has_many with at least two entrieshas_many 至少有两个条目
【发布时间】:2012-06-26 14:16:23
【问题描述】:

我需要一个至少有两个条目的 has_many 关联,我如何编写验证以及如何使用 RSpec + factory-girl 对其进行测试?这是我到现在为止得到的,但它以ActiveRecord::RecordInvalid: Validation failed: Bars can't be blank 失败,我完全陷入了 RSpec 测试。

/example_app/app/models/foo.rb

class Foo < ActiveRecord::Base
  has_many :bars
  validates :bars, :presence => true, :length => { :minimum => 2}
end

/example_app/app/models/bar.rb

class Bar < ActiveRecord::Base
  belongs_to :foo
  validates :bar, :presence => true
end

/example-app/spec/factories/foo.rb

FactoryGirl.define do
  factory :foo do
     after(:create) do |foo|
       FactoryGirl.create_list(:bar, 2, foo: foo)
     end
  end
end

/example-app/spec/factories/bar.rb

FactoryGirl.define do
  factory :bar do
    foo
  end
end

【问题讨论】:

  • :length 用于字符串,而不是关系。

标签: ruby-on-rails ruby rspec factory-bot


【解决方案1】:
class Foo < ActiveRecord::Base
  validate :must_have_two_bars

  private
  def must_have_two_bars
    # if you allow bars to be destroyed through the association you may need to do extra validation here of the count
    errors.add(:bars, :too_short, :count => 2) if bars.size < 2
  end
end


it "should validate the presence of bars" do
  FactoryGirl.build(:foo, :bars => []).should have_at_least(1).error_on(:bars)
end

it "should validate that there are at least two bars" do
  foo = FactoryGirl.build(:foo)
  foo.bars.push FactoryGirl.build(:bar, :foo => nil)
  foo.should have_at_least(1).error_on(:bar)
end

【讨论】:

  • 为了通过关联销毁,你需要这样做: if bars.select{ |bar| !bar.marked_for_destruction?}.size 2) end
  • 确实如此,我们的代码还检查了“销毁?”属性 ` bar_count = bar.reject { |bar| bar.destroyed? || bar.marked_for_destruction? }.size
【解决方案2】:

您想使用自定义验证器

class Foo < ActiveRecord::Base
  has_many :bars
  validate :validates_number_of_bars

  private
  def validates_number_of_bars
    if bars.size < 2
      errors[:base] << "Need at least 2 bars"
    end
  end
end

【讨论】:

  • 这很好,但我不会将方法命名为number_of_bars,因为它不是计算的。最好命名为 validates_number_of_bars 或让它实际返回数字,然后编写一个验证规则将其视为属性。
  • 当然,这只是一个例子
  • 没有理由说一个技术的例子不能同时是一个好的风格的例子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-23
  • 2015-10-24
  • 2022-01-13
相关资源
最近更新 更多