【问题标题】:Before validation method breaking spec with 'undefined method downcase'在验证方法破坏规范之前使用“未定义的方法小写”
【发布时间】:2017-12-21 00:39:34
【问题描述】:

在我的用户模型中,我有一个名为 normalize_params 的 before_validation 方法,它使用小写。

class User < ApplicationRecord
  before_validation :normalize_params, on: [:create, :update]

  validates :email, :presence => true
  validates :email, :uniqueness => true

  validates :username, :presence => true
  validates :username, :uniqueness => true

  validates_confirmation_of :password

  scope :all_users_except, -> (current_user) {
    where.not(id: current_user)
  }

  has_attached_file :avatar, styles: { medium: "300x300>", thumb: 
  "100x100>" }, default_url: "/images/missing.png"
  validates_attachment_content_type :avatar, content_type: 
  /\Aimage\/.*\z/
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
     :recoverable, :rememberable, :trackable, :validatable

  private

  def normalize_params
    self.name = name.downcase.titleize
    self.email = email.downcase
    self.home = home.downcase.titleize
  end
end

所有这些都在我的应用程序中完美运行,但是当我遇到此错误时,我的测试会中断...

NoMethodError:
  undefined method `downcase' for nil:NilClass

这是我的测试...

require 'rails_helper'

describe User, 'validation' do
  it { should validate_presence_of :email }
  it { should validate_presence_of :username }
  it { should validate_presence_of :password }
end

如果我去掉 before_validation 和 normalize_params,那么我的测试就通过了。

【问题讨论】:

    标签: ruby-on-rails validation rspec


    【解决方案1】:

    根据documentation 的示例,您可以在之前使用attribute_present?

    class User < ApplicationRecord
      before_validation :normalize_params, on: %i[create update]
    
      validates :email,    presence: true, uniqueness: true
      validates :username, presence: true, uniqueness: true
    
      private
    
      def normalize_params
        titleize_name
        downcase_email
        # You can any other here.
      end
    
      def titleize_name
        self.name = name.downcase.titleize if attribute_present? 'name'
      end
    
      def downcase_email
        self.email = email.downcase if attribute_present? 'email'
      end
    end
    

    注意你可以:

    • 使用%i[] 创建符号数组。
    • 通过逗号分隔来验证存在性和唯一性。
    • should 语法更喜欢is_expected.to (it { is_expected.to validate_presence_of :attribute })
    • 分离您的每个属性修改以便轻松工作并包含它们。
    • 在不需要时避免使用哈希火箭。见ruby-style-guide#hash-literals

    【讨论】:

    • 修复了它。也感谢您提供额外的信息。
    • TBH,除了样式偏好之外,shouldis_expected.to 对于内联期望(根据 RSpec 文档)绝对没有区别。我个人认为这只是更冗长而没有额外的好处。
    【解决方案2】:

    nameemailhome 之一可能是 nil。我建议使用safe navigation operator:

    def normalize_params
      self.name = name&.downcase&.titleize
      self.email = email&.downcase
      self.home = home&.downcase&.titleize
    end
    

    【讨论】:

    • 感谢发帖。这也解决了我的测试。我以前从未听说过安全导航操作员。
    • 哦,是的。我也花了一段时间才知道。它不是很普遍。 (在 Ruby 中,就是这样。有些语言在文档中往往会在你的脸上摩擦它哈哈)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多