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

我是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 

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

正如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并且被块记住,因为块是闭包

如果您将进一步阅读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,或irb你会看到:

 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! => #, , , >, , , , > 

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!

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

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