2011-10-28 3 views
7

私はルビーに新たなんだと私はシンプルなシナトラアプリで「メール」宝石を使用して、このような状況でエラーを取得していますなぜ不思議:メールブロックに自分の変数が表示されないのはなぜですか?

post "/email/send" do 

    @recipient = params[:email] 

    Mail.deliver do 
    to @recipient # throws error as this is undefined 
    from '[email protected]' 
    subject 'testing sendmail' 
    body 'testing sendmail' 
    end 

    erb :email_sent 

end 

これが正常に動作します:

post "/email/send" do 

    Mail.deliver do 
    to '[email protected]' 
    from '[email protected]' 
    subject 'testing sendmail' 
    body 'testing sendmail' 
    end 

    erb :email_sent 

end 

私はこれがブロックの範囲と私の誤解と関係があると考えています。

+1

あなたの問題は 'params [:email]'ではなく、インスタンスのvarであると確信していますか?あなたはそれを出力しようとしましたか?とにかくブロックがクロージャなので、ローカル変数もここで十分でなければなりません。 –

答えて

14

Julikが言うように、Mail#deliveryはブロックを実行している間だけで(あなたがそうでない場合はブロック内のメソッド#to#fromを呼び出すことができないだろう)selfを変更する、#instance_execを使用してブロックを実行します。

ここで実際にできることは、ブロックがクロージャであるという事実を使用することです。これは、その周りのすべてのローカル変数を「覚えている」ことを意味します。再び

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に依存せず、ブロックはクロージャであるため、ブロックによって記憶されます。
+0

少し追加:この動作はRubyのバージョンに依存しません。だから私は質問のタイトルから "Ruby 1.9"という言葉を削除すると、混乱するかもしれません。 –

+0

私の間違いはインスタンス変数を使用していたのですか?私はインスタンス変数を使用しました。なぜなら、そのデータをERBテンプレートで利用できるようにしたいと思ったからです。誤解されていなければ、インスタンス変数にする必要があります。ローカル変数を宣言するか、Tin Manが示唆するアプローチのいずれかを使用して、この問題を回避できます。おかげで、これまでRubyを愛していましたが、たくさん学ぶことができました:) –

3

メール宝石はフードの下でinstance_execを使用しているためだと思います。 instance_execは、呼び出し元からではなく呼び出されているオブジェクトからのインスタンス変数を使用します。私がやることは、インスタンストリックを使用せずに明示的な設定オブジェクトをブロックに渡してそこから処理するMail Gemのメソッドを見つけることです。いくつかの灰色の毛を惜しまない。

8

Mailのドキュメントをもう一度読むと、うまくいく別の解決策が見つかるはずです。むしろ使用より:

Mail.deliver do 
    to @recipient # throws error as this is undefined 
    from '[email protected]' 
    subject 'testing sendmail' 
    body 'testing sendmail' 
end 

あなたはパラメータを渡し、メールのnew()メソッドを使用して、ブロックを無視することができます。

Mail.new(
    to:  @recipient, 
    from: '[email protected]', 
    subject: 'testing sendmail', 
    body: 'testing sendmail' 
).deliver! 

または代替ハッシュ要素の定義:てこで

Mail.new(
    :to  => @recipient, 
    :from => '[email protected]', 
    :subject => 'testing sendmail', 
    :body => 'testing sendmail' 
).deliver! 

を、またはあなたが見るでしょう:

pry(main)> Mail.new(
pry(main)* to: '[email protected]', 
pry(main)* from: '[email protected]' << `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: [email protected]>, <To: [email protected]>, <Message-ID: <[email protected]>>, <Subject: test mail gem>, <Mime-Version: 1.0>, <Content-Type: text/plain>, <Content-Transfer-Encoding: 7bit>> 

newメソッドには、いくつかのバリエーションがあります。

さらに、Mail :: Messageオブジェクトを直接作成し、文字列、記号、またはダイレクトで値を渡して新しいメールを作成することもできますメソッド呼び出し。詳細については、Mail :: Messageを参照してください。mail.deliver!続い

mail = Mail.new 
mail.to = '[email protected]' 
mail[:from] = '[email protected]' 
mail['subject'] = 'This is an email' 
mail.body = 'This is the body' 

また、前の例では、メッセージエンベロープのさまざまなヘッダーにアクセスする複数の方法があることにも注意してください。それはよく考えられているように見え、Rubyのやり方にしっかりと従っている柔軟な宝石です。

+0

RubyGemsのものを見るのではなく、GitHubのドキュメントをあまりにも細かく見ていたでしょう。レッスンはそこで学んだ。再度、感謝します。 –

関連する問題