如何重现/清理凌乱的POST参数以避免使用delayed_job的YAML序列化问题?

Dir*_*nry 2 yaml ruby-on-rails delayed-job

今天,每当我开始delayed_job工作时,这个过程都会立即死而且无声无息.

经过一些调查(并找出前景模式delayed_job),我终于发现问题是delayed_job序列化我的活动记录对象在YAML加载部分触发异常的方式:

Psych::SyntaxError: (<unknown>): mapping keys are not allowed in this context at line 7 column 14
from /Users/mick/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/1.9.1/psych.rb:203:in `parse'
from /Users/mick/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/1.9.1/psych.rb:203:in `parse_stream'
from /Users/mick/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/1.9.1/psych.rb:151:in `parse'
from /Users/mick/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/1.9.1/psych.rb:127:in `load'
from /Users/mick/.rvm/gems/ruby-1.9.3-p448/gems/safe_yaml-0.9.7/lib/safe_yaml.rb:144:in `load_with_options'
from (irb):111
from /Users/mick/.rvm/gems/ruby-1.9.3-p448/gems/railties-3.2.16/lib/rails/commands/console.rb:47:in `start'
from /Users/mick/.rvm/gems/ruby-1.9.3-p448/gems/railties-3.2.16/lib/rails/commands/console.rb:8:in `start'
from /Users/mick/.rvm/gems/ruby-1.9.3-p448/gems/railties-3.2.16/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
Run Code Online (Sandbox Code Playgroud)

delayed_job尝试时发生了什么:

YAML.load(my_job.handler)
Run Code Online (Sandbox Code Playgroud)

(其他人在我面前有同样的问题)

找到有问题的Delayed::Backend::ActiveRecord::Job实例后,puts my_job.handler会显示:

object: !ruby/ActiveRecord:MyActiveRecord
  attributes:
    id: 7648
    ... some good stuff ...
    my_field: ?   bla bla bla
    ... some other good stuff ...
method_name: :mail
args: []
Run Code Online (Sandbox Code Playgroud)

我首先认为这是一个编码问题,但我意识到'?' 性格是一个真正的'?' 字符(即值63)而不是对未识别字符的误解.

然后我尝试使用值创建我的活动记录类的新实例my_field,? Totot但是YAML看起来如下所示:

object: !ruby/ActiveRecord:MyActiveRecord
  attributes:
    id: 7648
    ... some good stuff ...
    my_field: ! '?   bla bla bla'
    ... some other good stuff ...
method_name: :mail
args: []
Run Code Online (Sandbox Code Playgroud)

YAML.load(...)成功地跑了.

所以我的问题是:

  1. 知道我的数据库中有多乱的YAML吗?
  2. 知道我应该如何消毒我的params以避免这样的问题?
  3. 知道如何在单元测试中重现这一点吗?(可以肯定我实际上正在修改第2步)

Abd*_*bdo 5

@ house9建议的详细解释:

不要执行以下操作(即使delayed_job的git repo建议为例)

Notifier.delay.signup(@user)

class NotifierMailer < ActionMailer::Base
  def signup(user)
  end
end
Run Code Online (Sandbox Code Playgroud)

因为这将尝试yaml编码@user(这可能会导致问题)

但是,每当你有一个具有id的对象(尤其是AR对象)时,你应该在调用延迟的作业时传递id并在以后检索它:

Notifier.delay.signup(@user.id)

class NotifierMailer < ActionMailer::Base
  def signup(id)
     @user = User.find_by_id(id)
  end
end
Run Code Online (Sandbox Code Playgroud)