【问题标题】:rails, rspec, shoulda validate_presence_of failed with setter called twicerails, rspec, shoulda validate_presence_of 失败,setter 调用了两次
【发布时间】:2013-04-23 17:29:36
【问题描述】:

在带有公司模型的简单 Rails 应用中

class Company < ActiveRecord::Base

  # Attributes
  attr_accessible :name

  validates_presence_of :name

  def name=(s)
    self[:name] = s.upcase
  end
end

运行以下规范文件时。它失败。

require 'spec_helper'

describe Company do

  before :each do
    @company = Company.new({name: 'my_company'})
  end

  it "should validate presence of name" do
    @company.should validate_presence_of(:name)
  end

end

调试显示 name=(s) 方法被调用了两次,一次使用“my_company”,一次使用 nil。

我不明白为什么 nill 会发生第二次调用。 以下是使用的宝石:

gem 'rails', '3.2.13'
gem 'mysql2' 

group :development, :test do
  gem 'rspec-rails', '2.11.0' 
  gem 'shoulda-matchers', :require => false
end

【问题讨论】:

    标签: ruby-on-rails rspec2 shoulda


    【解决方案1】:
    • 应该用于编写文档中提到的一种衬里规格,例如
      它{应该 validate_presence_of(:name)}
      它 { 应该 validate_presence_of(:name).with_message(/不是可选的/) }

      因此,您可以以更易读的方式编写规范,如下所示:

      描述'验证'做
       它{应该 validate_presence_of(:name)}
       结束
    • 关于您对 name 字段的两个分配的问题:

      1. 第一次分配是在您规范的 before(:each) 块中完成的,并且
      2. 应该存在验证器尝试为您指定要验证存在的所有属性分配 nil 值,如果您的模型是 :name
        您覆盖的 name= 方法发生在这个 nil 值上,它会引发错误,因为它不能大写 nil。出于同样的原因,上面显示的一种衬里规格也会失败。为了解决这个问题,你可以改变你的setter方法来做s.try(:upcase)。所以它可以在 nil 值上工作并且不会引起任何问题。

    【讨论】:

    • 关于你的 2. 你从哪里得到这些信息?“应该存在验证器尝试为所有属性分配 nil 值”。我仍然不明白为什么该方法被调用两次。第一次调用名称为值,第二次调用为空。
    • @alpha,我浏览了should的代码validate_presence_of_matcher。有一个方法matches?,内部调用disallows_value_of(blank_value , @expected_message)。如果您遵循此代码,您将看到在 AllowValueMatcher 的 matches? 方法中完成对 nil 值的赋值
    【解决方案2】:

    原因可能是你在新的name 方法中提到了name

    最好使用write_attribute 方法作为您引用的文档。

    读作:

     def name=(s)
       write_attribute(:name, s.upcase)
     end
    

    【讨论】:

    • 第二种方法name=修改name的值,所以需要。正确的方法应该是什么?并且没有解释为什么第二次调用有一个空值参数
    • @Alpha,是的,我知道你需要它,但你不需要写那个 def,因为attr_accessible :name 已经为你自动生成了这个方法。删除该 def,您的代码就可以工作了。
    • 你不会混淆 attr_accessible 和 attr_accessor 吗?如果您删除 attr_accessible 您会得到“无法批量分配受保护的属性:名称”,api.rubyonrails.org/classes/ActiveRecord/… 似乎也以我的方式显示它
    • @Alpha,是的,我的错。但是您没有遵循相同的方式,您在新的name 方法中提到了name,我来宾这就是错误的原因。查看文档,他们使用write_attribute,这应该是正确的方式。
    • 查看文档底部“您可以选择使用 self[:attribute]=(value) 和 self[:attribute] 而不是 write_attribute(:attribute, value) 和 read_attribute(:attribute) 。”我猜 self[:name]=s.upcase 是有效的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-10
    • 1970-01-01
    相关资源
    最近更新 更多