Почему блок Mail не видит мою переменную? - PullRequest
8 голосов
/ 28 октября 2011

Я новичок в Ruby и удивляюсь, почему я получаю сообщение об ошибке в этой ситуации, используя гем 'mail' в простом приложении Sinatra:

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 ]

14 голосов
/ 28 октября 2011

Как говорит Джулик, 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 и запоминаются блоками, потому что блоки замыкания .
10 голосов
/ 28 октября 2011

Если вы прочитаете документы для 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!
=> #<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.

3 голосов
/ 28 октября 2011

Я думаю, это потому, что самоцвет Mail использует instance_exec под капотом. instance_exec использует переменные экземпляра из объекта, к которому он вызывается, а не из вызывающей стороны. Я бы нашел в геме Mail метод, который не использует уловки экземпляров, а передает явный объект конфигурации в блок и продолжает с него. Щадит несколько седых волосков.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...