为什么Mail块看不到我的变量?

时间:2011-10-28 11:52:20

标签: ruby sinatra

我是Ruby的新手,想知道为什么我在一个简单的Sinatra应用程序中使用'mail'gem来解决这种情况的错误:

post "/email/send" do

  @recipient = params[:email]

  Mail.deliver do 
    to @recipient # throws error as this is undefined
    from 'server@domain.com'
    subject 'testing sendmail'
    body 'testing sendmail'
  end

  erb :email_sent

end

然而这很好用:

post "/email/send" do

  Mail.deliver do 
    to 'me@domain.com'
    from 'server@domain.com'
    subject 'testing sendmail'
    body 'testing sendmail'
  end

  erb :email_sent

end

我怀疑这与块范围以及我对它的误解有关。

3 个答案:

答案 0 :(得分:14)

正如Julik所说,Mail#delivery使用#instance_exec执行您的阻止,只是在运行阻止时更改self(您将无法调用方法#to和否则在块内#from

你真正可以做的是使用块闭包的事实。这意味着它“记住”了它周围的所有局部变量。

recipient = params[:email]
Mail.deliver do 
    to recipient # 'recipient' is a local variable, not a method, not an instance variable
...
end

再次,简要地说:

  • 实例变量和方法调用取决于self
  • #instance_exec更改self;
  • 局部变量不依赖于self并且会被块记住,因为块闭包

答案 1 :(得分:10)

如果您将进一步阅读Mail的文档,您将找到一个可行的替代解决方案。而不是使用:

Mail.deliver do 
  to @recipient # throws error as this is undefined
  from 'server@domain.com'
  subject 'testing sendmail'
  body 'testing sendmail'
end

您可以使用Mail的new()方法,传入参数,并忽略该块:

Mail.new(
  to:      @recipient,
  from:    'server@domain.com',
  subject: 'testing sendmail',
  body:    'testing sendmail'
).deliver!

或备用哈希元素定义:

Mail.new(
  :to      => @recipient,
  :from    => 'server@domain.com',
  :subject => 'testing sendmail',
  :body    => 'testing sendmail'
).deliver!

撬开,或者你会看到:

pry(main)> Mail.new(
pry(main)* to: 'me@domain.com',
pry(main)* from: 'me@' << `hostname`.strip,
pry(main)* subject: 'test mail gem',
pry(main)* body: 'this is only a test'
pry(main)* ).deliver!
=> #<Mail::Message:59273220, Multipart: false, Headers: <Date: Fri, 28 Oct 2011 09:01:14 -0700>, <From: me@myhost.domain.com>, <To: me@domain.com>, <Message-ID: <4eaad1cab65ce_579b2e8e6c42976d@myhost.domain.com>>, <Subject: test mail gem>, <Mime-Version: 1.0>, <Content-Type: text/plain>, <Content-Transfer-Encoding: 7bit>>

new方法有几种可供使用的变体。这也来自文档,可能会更好:

  

作为旁注,您还可以通过直接创建Mail :: Message对象,然后通过字符串,符号或直接方法调用传递值来创建新电子邮件。有关详细信息,请参阅Mail :: Message。

 mail = Mail.new
 mail.to = 'mikel@test.lindsaar.net'
 mail[:from] = 'bob@test.lindsaar.net'
 mail['subject'] = 'This is an email'
 mail.body = 'This is the body'

后跟mail.deliver!

另请注意,在前面的示例中,有多种方法可以访问邮件信封中的各种标头。它是一个灵活的宝石,似乎经过深思熟虑,很好地遵循Ruby方式。

答案 2 :(得分:3)

我认为这是因为Mail gem使用了instance_execinstance_exec使用来自正在调用的对象的实例变量,而不是来自调用者。我要做的是在Mail gem中找到一个不使用实例技巧但是将显式配置对象传递给块的方法,然后从那里开始。少量白发。