为什么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_exec
。 instance_exec
使用来自调用它的对象的实例变量,而不是来自调用者。 我要做的是在Mail gem中找到一个不使用实例技巧的方法,但是将一个显式配置对象传递给该块,然后从那里开始。 少量白发。