【问题标题】:Rails: Continue to save other attributes despite validation error in one of themRails:尽管其中一个属性出现验证错误,但仍继续保存其他属性
【发布时间】:2015-03-25 10:39:19
【问题描述】:

我正在使用 Delayed_Job 处理从 Amazon S3 存储桶中检索到的回形针图像。

我试图解决的基本问题是在处理回形针图像时发生验证错误时能够保存在数据库中。

我的基本代码如下:

class Provider < ActiveRecord::Base

    after_save :queue_image_processing, if: Proc.new {|provider| provider.image_s3_key}

    has_attached_file :image, styles: {original: "1000x1000", medium: "530x530#", thumb: "300x300#"}, default_url: "/default-avatar_:style.png"

    validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/

    def self.process_image(id)

        provider = Provider.find(id)
        s3_image_object = S3_BUCKET.objects[provider.image_s3_key]

        begin
            provider.image = s3_image_object.public_url
            provider.image_s3_key = nil
            provider.image_started_processing_at = nil
            provider.error = false
            provider.save!
        rescue ActiveRecord::RecordInvalid
           logger.info "$$$$$ Record Invalid called $$$$"
           provider.image_s3_key = nil
           provider.image_started_processing_at = nil
           provider.error = true
           provider.save
        end
    end

    private

     def queue_image_processing
         Provider.delay.process_image(id)
     end

结束

当图像的格式不正确时(例如,由于文件扩展名的欺骗),将执行回滚,即保存!抛出 ::RecordInvalid。这一切都很好,并且显示了 logger.info 中的调试文本。

我遇到的问题是救援子句中的其余代码似乎没有被执行(即那些属性没有存储在数据库中)。

这段代码只是我做过的几次尝试之一,但我的基本需求是能够编写在数据库中没有收到验证错误的其他属性。如您所见,我需要小心,因为我有一个 after_save 回调,并且需要避免多次调用此回调(以及因此运行此回调的条件)。

非常感谢所有帮助!提前致谢

PS:Rails 4.0

【问题讨论】:

  • 是代码没有执行还是记录没有持久化?值得检查您的记录是否仍然无效并且save 因此返回错误。
  • 是的,在阅读了文档和示例here 之后,您实际上是对的。代码被执行(我也知道这也是因为显示了救援代码中的调试字符串),但记录仍然无效。我想知道是否有办法“重置”有效性(指南明确说我不能使用errors.clear,因为这不会改变对象的有效性)......

标签: ruby-on-rails amazon-s3 paperclip delayed-job


【解决方案1】:

实际上我找到了方法,这要归功于 David Verhasselt 在Different ways to set attributes in Rails 上的方便备忘单。

这可能不是最纯粹的方法,但嘿,它有效。

方法是使用model.update_columns:

def self.process_image(id)
    provider = Provider.find(id)
    s3_image_object = S3_BUCKET.objects[provider.image_s3_key]

    begin
      provider.image_s3_key = nil
      provider.image_started_processing_at = nil
      provider.error = false
      provider.image = s3_image_object.public_url
      provider.save!
    rescue ActiveRecord::RecordInvalid
      logger.info "$$$$$ Record Invalid called $$$$"
      provider.update_columns(image_s3_key: nil, image_started_processing_at: nil, error: true)
    end
end

这有额外的好处(在我的情况下,但可能不适合所有情况)updated_at 不更新,不执行验证并且不调用回调。在我的情况下,这很好,因为在用户操作后记录不会更新,而只是由于失败。

希望这对其他人有所帮助。

【讨论】:

    猜你喜欢
    • 2014-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-03
    • 1970-01-01
    • 1970-01-01
    • 2017-12-28
    相关资源
    最近更新 更多