Rails rails 数据检验在什么时候执行?

caiqinghua · 2015年07月23日 · 最后由 caiqinghua 回复于 2015年07月24日 · 2006 次阅读

一、先上代码

class Variant
    validate :check_price

      # Ensures a new variant takes the product master price when price is not supplied
      def check_price
        if price.nil? && Config[:require_master_price]
          raise 'No master variant found to infer price' unless (product && product.master)
          raise 'Must supply price for variant or master.price for product.' if self == product.master
          self.price = product.master.price
        end
        if currency.nil?
          self.currency = Config[:currency]
        end
      end

class LineItem
    belongs_to :variant, inverse_of: :line_items

    before_validation :copy_price

    def copy_price
      if variant
        update_price if price.nil?
        self.cost_price = variant.cost_price if cost_price.nil?
        self.currency = variant.currency if currency.nil?
      end
    end

二、数据库

variant 数据库列中没有 currency 列

+----+-----------+--------+--------+-------+-------+------------+-----------+------------+------------+------------+----------+-------------+------------+-------------+------------+
| id | sku       | weight | height | width | depth | deleted_at | is_master | product_id | cost_price | cost_cu... | position | track_in... | tax_cat... | updated_at  | stock_i... |
+----+-----------+--------+--------+-------+-------+------------+-----------+------------+------------+------------+----------+-------------+------------+-------------+------------+
| 1  | R00011 | 0.0    |        |       |       |            | true      | 1          | 17.0       | USD        | 2        | true        |            | 2015-07-... | 1          |
+----+-----------+--------+--------+-------+-------+------------+-----------+------------+------------+------------+----------+-------------+------------+-------------+------------+
1 row in set

三、Active Record 数据验证

以下方法会做数据验证,如果验证失败就不会把对象存入数据库: create create! save save! update update!

四、问题

问题:variant 数据库列中没有 currency 列,所以不能持久化,但是 LineItem 中能使用 variant.currency,难道每次 variant 数据出库会执行 validate :check_price 吗? validate :check_price 在数据创建和读取都会调用吗?read 方法也会执行数据验证吗?

#1 楼 @caiqinghua 理论上应该不会,看这里的文档: Custom Methods

By default such validations will run every time you call valid?

还有个问题,看你的代码不像是为了做校验,更像是一个初始化操作(在缺失 currency 的时候配置 currency 值),这样的代码建议改为 callback 更好。

说到 callback,可以检查是不是你的代码里有类似于这样的 callback 声明?

class Variant
  after_initialize :check_price     # after_initialize 就是在对象实例化(从数据库中读数据也是要经历这个阶段的)之后调用的 callback ,这个更符合你的业务逻辑才对

我觉得更有可能是这样的 callback 起的作用,这样也才更合理

#2 楼 @martin91 代码没贴全,check_price 确实检查了价格。可能是 spree 的 bug?

#3 楼 @caiqinghua 是 spree 的哪个版本呢?

#4 楼 @martin91 最新版本 master 分支

需要 登录 后方可回复, 如果你还没有账号请 注册新账号