如何根据关联的属性验证模型?

时间:2017-11-04 00:46:28

标签: ruby-on-rails validation ruby-on-rails-4 rspec model

在Rails4中,我有一个属于另一个模型的模型。如何根据父模型中的属性值进行验证?

在食物菜单系统中,有属于类别的类别和菜肴。某些类别有多种尺寸。如果有多种尺寸,那么必须有大小的名称;这些将用作视图中的标签。这可以通过presence: true, if: :multi_size?

进行验证

现在,如果菜肴属于多尺寸的类别,那么我想验证这两种尺寸都有价格。如果菜肴属于单一尺寸类别,则使用大尺寸价格,因此必须始终存在。但是,只有在类别大小的情况下才需要小尺寸的价格。

我尝试制作方法以查看该类别是否为多尺寸,但我在irb中收到此错误:NoMethodError: private method 'multi_size_category' called for #<Dish:0x007ffebd2827b0>

在rspec中,我收到此错误:NoMethodError: undefined method 'multi_size' for nil:NilClass

# == Schema Information
#
# Table name: categories
#
#  id              :integer          not null, primary key
#  name            :string
#  description     :string
#  multi_size      :boolean
#  small_size_name :string
#  large_size_name :string

class Category < ActiveRecord::Base
  has_many :dishes

  validates :name,               presence: true
  validates :small_size_name,    presence: true, if: :multi_size?
  validates :large_size_name,    presence: true, if: :multi_size?
end

# == Schema Information
#
# Table name: dishes
#
#  id               :integer          not null, primary key
#  name             :string
#  category_id      :integer
#  description      :string
#  small_size_price :decimal(, )
#  large_size_price :decimal(, )

class Dish < ActiveRecord::Base
  belongs_to :category, required: true

  validates :name,               presence: true
  validates :category_id,        presence: true
  validates :small_size_price,   presence: true, if: :multi_size_category?
  validates :large_size_price,   presence: true
  validates_numericality_of :large_size_price

  private

  def multi_size_category?
    self.category.multi_size
  end

end

这是菜的工厂:

FactoryGirl.define do
  factory :dish do
    name Faker::Food.dish
    association :category, factory: :category
    description Faker::Lorem.sentence
    small_size_price Faker::Number.decimal(2)
    large_size_price Faker::Number.decimal(2)
  end
end

1 个答案:

答案 0 :(得分:1)

您似乎试图直接在控制台中调用dish.multi_size_category?,这导致了您的第一个问题(它是一个私有方法)。第二个错误发生的原因是您没有在工厂中设置菜肴的类别(因此self.category为零)。您可能希望首先确保测试对象有效。

就个人而言,我觉得您的数据结构过于严格,并且存在应该删除的依赖项。例如,类别不应该知道关于菜肴大小的任何信息(即单一责任)。

最好有四个类:Category,Dish,Size和DishSize,其中category_many菜。菜肴通过dish_sizes表有多种大小,您可以在其中指定每种菜肴/大小组合的名称和价格。通过这种方式,您可以自由创建新的尺寸(可能是中等尺寸?),您只需要验证DishSize是否有价格和名称。