开发者

Rails 3: Mail::Message cannot be delivered after serializing

开发者 https://www.devze.com 2023-03-05 06:15 出处:网络
I want to serialize a Mail::Message object in order to store it in the database and send it later. My first attempt was to use the built-in serialize method of ActiveRecord like this:

I want to serialize a Mail::Message object in order to store it in the database and send it later. My first attempt was to use the built-in serialize method of ActiveRecord like this:

class Email < ActiveRecord::Base
  serialize :mail

  # ...

end

Unfortunately, trying to save the record resulted in an exception

> 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'
    (...)

So I simply created a custom accessor using the to_yaml / from_yaml functions of Mail::Message. But now I experience this strange behaviour:

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 - c开发者_Go百科onnect(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>'

Any idea on how to solve this problem? Why does serializing the object to yaml make the Message object undeliverable? Is there maybe another method to properly serialize the Message object to send it later?


I realized the mail_clone object did not have proper delivery settings, which caused the failure of the deliver call. Browsing through the Rails sourcecode, I found the following solution:

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

So this might be a way to serialize the Mail::Message object:

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


Does specifying the class name help?

serialize :mail, 'Mail::Message' 
0

精彩评论

暂无评论...
验证码 换一张
取 消