【问题标题】:Rails 3: Mail::Message cannot be delivered after serializingRails 3:序列化后无法传递 Mail::Message
【发布时间】:2011-05-12 18:31:45
【问题描述】:

我想序列化一个Mail::Message 对象,以便将其存储在数据库中并稍后发送。 我的第一次尝试是像这样使用 ActiveRecord 的内置 serialize 方法:

class Email < ActiveRecord::Base
  serialize :mail

  # ...

end

很遗憾,尝试保存记录导致异常

> foo.save
ArgumentError: wrong number of arguments (1 for 0)
from /home/akrueger/.rvm/gems/ruby-1.9.2-p180/gems/mail-2.2.19/lib/mail/message.rb:1714:in `to_yaml'
from /home/akrueger/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:55:in `accept'
from /home/akrueger/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:36:in `<<'
from /home/akrueger/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/psych.rb:165:in `dump'
from /home/akrueger/.rvm/gems/ruby-1.9.2-p180/gems/activerecord-3.0.7/lib/active_record/base.rb:1720:in `block in arel_attributes_values'
    (...)

所以我只是使用Mail::Message 的to_yaml / from_yaml 函数创建了一个自定义访问器。但现在我遇到了这种奇怪的行为:

mail_original = UserMailer.user_welcome_email(@user)
=> #<Mail::Message:93415800, Multipart: false, Headers: <From: (...) >, <To: (...) >, <Subject: (...) >, <Mime-Version: 1.0>, <Content-Type: text/plain>>
mail_clone = Mail::Message.from_yaml mail_original.to_yaml
=> #<Mail::Message:92940980, Multipart: false, Headers: <Date: (...) >, <From: (...) >, <To: (...) >, <Message-ID: (...) >, <Subject: (...) >, <Mime-Version: 1.0>, <Content-Type: text/plain>, <Content-Transfer-Encoding: quoted-printable>>
mail_original.deliver
=> #<Mail::Message:93415800, Multipart: false, Headers: <Date: (...) >, <From: (...) >, <To: (...) >, <Message-ID: (...) >, <Subject: (...) >, <Mime-Version: 1.0>, <Content-Type: text/plain>, <Content-Transfer-Encoding: quoted-printable>>
mail_clone.deliver
Errno::ECONNREFUSED: Connection refused - connect(2)
from /home/akrueger/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/net/smtp.rb:546:in `initialize'
from /home/akrueger/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/net/smtp.rb:546:in `open'
from /home/akrueger/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/net/smtp.rb:546:in `tcp_socket'
from /home/akrueger/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/net/smtp.rb:555:in `block in do_start'
from /home/akrueger/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/timeout.rb:57:in `timeout'
from /home/akrueger/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/timeout.rb:87:in `timeout'
from /home/akrueger/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/net/smtp.rb:555:in `do_start'
from /home/akrueger/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/net/smtp.rb:525:in `start'
from /home/akrueger/.rvm/gems/ruby-1.9.2-p180/gems/mail-2.2.19/lib/mail/network/delivery_methods/smtp.rb:128:in `deliver!'
from /home/akrueger/.rvm/gems/ruby-1.9.2-p180/gems/mail-2.2.19/lib/mail/message.rb:1989:in `do_delivery'
from /home/akrueger/.rvm/gems/ruby-1.9.2-p180/gems/mail-2.2.19/lib/mail/message.rb:232:in `deliver'
from (irb):68
from /home/akrueger/.rvm/gems/ruby-1.9.2-p180/gems/railties-3.0.7/lib/rails/commands/console.rb:44:in `start'
from /home/akrueger/.rvm/gems/ruby-1.9.2-p180/gems/railties-3.0.7/lib/rails/commands/console.rb:8:in `start'
from /home/akrueger/.rvm/gems/ruby-1.9.2-p180/gems/railties-3.0.7/lib/rails/commands.rb:23:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'

关于如何解决这个问题的任何想法?为什么将对象序列化为 yaml 会使Message 对象无法传递?是否有另一种方法可以正确序列化 Message 对象以便稍后发送?

【问题讨论】:

  • 找到了解决方案:添加ActionMailer::Base.wrap_delivery_behavior mail_clone确保mail_clone的投放设置正确。我会尽快将其发布为答案。

标签: ruby-on-rails-3 yaml actionmailer


【解决方案1】:

我意识到mail_clone 对象没有正确的传递设置,导致deliver 调用失败。浏览 Rails 源码,找到如下解决方案:

mail_clone = Mail::Message.from_yaml mail_original.to_yaml
ActionMailer::Base.wrap_delivery_behavior mail_clone
mail_clone.deliver

所以这可能是一种序列化Mail::Message对象的方法:

class Email < ActiveRecord::Base
  def mail
    @mail_cached || begin
      m = Mail::Message.from_yaml(self.read_attribute :mail)
      ActionMailer::Base.wrap_delivery_behavior m
      m
    rescue
      nil
    end
  end

  def mail=(val)
    @mail_cached = val
    write_attribute :mail, val.to_yaml
  end

  # ...
end

【讨论】:

  • 这帮助我序列化 Mail::Message。只有serialize :mail, Mail::Message 我得到了错误TypeError: allocator undefined for Encoding。我使用 Rails 4.1
【解决方案2】:

指定类名有帮助吗?

serialize :mail, 'Mail::Message' 

【讨论】:

  • 很遗憾没有。我不得不将其更改为 serialize :mail, Mail::Message 并将列默认值设置为 NULL,但随后它只会引发与首先描述的相同的异常(ArgumentError: wrong number of arguments (1 for 0),在 to_yaml)
  • 如果我是你(不知道你的业务需求),我只会将邮件对象的属性存储为序列化数组,然后在以后需要实际发送时构建一个新的邮件对象。
  • 感谢您的建议。如果没有其他帮助,我可能会听从您的建议。不过,我想知道是否有更“有条理”的解决方案。
猜你喜欢
  • 2023-03-20
  • 2011-08-20
  • 2011-04-19
  • 1970-01-01
  • 2011-05-06
  • 1970-01-01
  • 2014-11-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多