【问题标题】:Rails conditional validation: if: doesn't workingRails 条件验证:如果:不起作用
【发布时间】:2021-10-19 18:12:39
【问题描述】:

我是 Rails 新手,我有一个带有三个外键的 trip 课程。其中两个将其与同一类相关联:Place。

这是我的模型:

class Trip < ApplicationRecord
    belongs_to :from, class_name: "Place", foreign_key: "from_id"
    belongs_to :to, class_name: "Place", foreign_key: "to_id"
    belongs_to :vehicle, class_name: "Vehicle", foreign_key: "vehicle_id"

    validates :price, presence: true
    validates :time, presence: true
    validates :from_id, presence: true
    validates :to_id, presence: true, if: :from_different_to?
    
    def from_different_to?
        to_id != from_id
    end
end

除最后一项外,所有模型测试均通过:

class TripTest < ActiveSupport::TestCase

  def setup
    @place1 = Place.create(name:"NewYork",cap:"11111",lat:"1234",long:"1478")
    @place2 = Place.create(name:"Los Angeles", cap:"22222", lat:"1234",long:"1478")
    @vehicle = Vehicle.create(targa: "ab123cd",modello:"500",marca:"Fiat", posti:5,alimentazione:"benzina")
    @trip = Trip.new(price: 10, time: Time.new(2021, 10, 14, 12,03), from_id: @place1.id, to_id: @place2.id,vehicle_id: @vehicle.id)  
  end
...

test "Departure id and arrival id should be different" do
    @trip.to_id = @place1.id
    assert_not @trip.valid?
  end

导致失败的:

Failure:
TripTest#test_Departure_id_and_arrival_id_should_be_different [/media/alessandro/DATA/Universita/Magistrale/1_anno/Programmazione_concorrente/hitchhiker/test/models/trip_test.rb:45]:
Expected true to be nil or false

我无法理解为什么。 有人可以帮我吗?

【问题讨论】:

  • @spickermann 记录是有效的,但他们希望它不是。我不知道为什么。
  • @spickermann 在设置中我设置了to_id: @place2.id,但在测试中我设置了@trip.to_id = place1.id,所以to_id == from_id == @place1.id。这是因为如果模型有效拒绝此记录,我想尝试一次无效的旅行

标签: ruby-on-rails ruby testing


【解决方案1】:

您似乎认为validates ... if: 的工作方式与实际不同。这一行

validates :to_id, presence: true, if: :from_different_to?

如果from_different_to 方法返回true,则转换为验证to_id 是否存在。当from_different_to 评估为false 时,不进行验证。见Rails Guides

这意味着当你定义时

@trip.to_id = @place1.id
assert_not @trip.valid?

在您的测试中,第一行禁用检查to_id 的存在。没有验证,没有错误...

我想你真正想要实现的是验证 to_id 是否存在 并且 from_idto_id 不相等。这可以通过custom validation 来完成,如下所示:

validates :to_id, presence: true
validate :validates_places_are_different

private
def validates_places_are_different
  errors.add(:to_id, "must be different to from_id") if to_id == from_id
end

【讨论】:

  • 是的,您遇到了问题。我误解了if: 的工作原理。谢谢你的回答,我解决了我的问题,不幸的是我没有必要的声誉给你+1,但你的帮助是无价的。
【解决方案2】:

我无法理解为什么。有人可以帮我吗?

if 有条件地启用验证。您的 to_idfrom_id 相同,因此 to_id 根本没有经过验证。但即使是这样,to_id 也有一个值,因此该字段不会出现错误。


总体而言,我不太确定您为什么会在这里期待验证错误或该错误应该是什么。根据我的经验,像assert_not @model.valid? 这样的断言实际上是没有用的。由于不相关的原因,该记录可能无效,您将不知道。就个人而言,我断言我所期望的确切错误消息。这些方面的东西(rspec 语法)

it "requires first_name" do
  expected_messages = {
    first_name: [:blank],
  }

  @model.valid?
  expect(@model.errors.full_messages).to eq expected_messages
end

【讨论】:

  • 概念是:from_id和to_id是相等的,所以如果@trip.valid?return false,说明我的模型(Trip)已经拒绝了记录(应该怎么做),assert_not false =>测试通过。问题是我的模型没有拒绝记录,所以我的问题是为什么会发生这种情况?
  • @AleCrout 是的,我了解assert_not @trip.valid? 的工作原理。我的问题是,我不明白您为什么希望该模型有效。但看起来 spickermann 给了你一个更好的答案。
【解决方案3】:

@spickermann 的替代方案是:

class Trip < ApplicationRecord
    belongs_to :from, class_name: "Place", foreign_key: "from_id"
    belongs_to :to, class_name: "Place", foreign_key: "to_id"
    belongs_to :vehicle, class_name: "Vehicle", foreign_key: "vehicle_id"

    validates :price, presence: true
    validates :time, presence: true
    validates :from_id, presence: true
    validates :to_id, numericality: {other_than: :from_id}, if: :from_place_id?

    def from_place_id
        from_id
    end

    def from_place_id?
        !from_id.nil?
    end
end

请注意,只有当 from_id 不为 null 时,我们才必须放置一个控件来执行最后的验证,因为如果我们不这样做,我们会在上一行中虚化控件 validates :from_id, presence:true

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-20
    • 2020-05-15
    • 1970-01-01
    • 2017-07-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多