2005年12月15日

Ruby on Rails 1.0

ついに出ましたな。 今まで書いたコードも全部1.0ベースでチェックし直すかな。

2006年4月12日

ActionView::Helpers::FormHelperをlocal varibaleで使いたい

今回はRailsの話。 local variableに対してFormHelperを使いたくなることがあります。 例えば、eachでぶんまわしたいときなんかが典型例です。 でも、ひとつめの引数object_nameからinstance variableを取りに行くので、 こりゃどうしたもんじゃいと思ってました。

で、コードを読んで目から鱗。なんと、optionsでオブジェクトを指定できるではないですか!! ドキュメントも端から端まで読むと確かにかいてーる。 例えば以下のような感じですな。

@users.each do |user|
  text_field 'user', 'name', :object => user, :name => 'user[]'
end

この例ではnameにuser[]なんてやってるので実質役に立ちませんが、 オブジェクトを指定できるのはほんとに目から鱗でした。

2006年4月20日

続:ActionView::Helpers::FormHelperをlocal varibaleで使いたい

先日、FormHelperでobjectを指定する方法について書きましたが、 Rails 1.1からはform_forとfieldsforを使って同様のことができるようになったようです。 正しい使い方なのかなんだかよくわかりませんが、

@users.each do |user|
  fields_for :user, user do |u|
    u.text_field :name, :name => 'user[]'
  end
end

みたいな感じ。どっちがいいというわけではなくて、使い分ければいいんじゃないかと思います。

2007年3月 3日

ActionMailerでenvelope-fromを指定する

メールを送信する場合、ヘッダに現れるFromのほかにenvelope-fromという「本当の」送信者をしています。これはSMTPでお話しするときに指定するので、実際にMUAでメールを読むときには、表面的には現れません。最終ホップ(すなわち、local mailerに落とすMTA)がReturn-Pathというヘッダ・フィールドを付加してenvelope-fromを保存するので、かろうじてこれでみることができます。

さて、envelope-fromがどうして大事かというと、エラーが発生したときに通知するアドレスとして利用されるからです(大昔はErrors-Toなんてヘッダ・フィールドを使ってたこともありましたが、さすがにもうないでしょう)。たとえば、メーリング・リストなんかでは、エラーが実際の送信者にいってもうれしくないですし、ましてやメーリング・リスト本体に送信されちゃっても困るわけで、envelope-fromとしてはメーリング・リストの管理者にしたりするわけですね。

ところで、ActionMailerですが。こいつでメールを送信するときのenvelope-fromは自由に設定できません。こりゃこまるだろーというのが今回の話。

たとえば以下のコード。

class TestMail < ActionMailer::Base
  def test1
    subject  "Test"
    from     "test-ml@example.com"
    body     "Please ignore."
  end
end

これでTestMail.deliver_test1とかやるとメールが飛んでいくわけですが、envelope-fromはもれなくtest-ml@example.comになります。もちろんこのままでいいときもあるわけですが、多くの場合、エラーは別途処理したいと思うので、異なるアドレスをenvelope-fromに指定したいでしょう。

というわけで、以下のパッチが役に立つかも?本家にもチケットあげたので、そのうち反映されるかもしれません…が、今まで投げつけたチケットはことごとく無視されてるか、すげー反応が遅いかって感じなので、期待薄かもしれない。

Index: lib/action_mailer/base.rb
===================================================================
--- lib/action_mailer/base.rb	(revision 6287)
+++ lib/action_mailer/base.rb	(working copy)
@@ -36,6 +36,7 @@
   # * <tt>from</tt> - Who the email you are sending is from. Sets the <tt>From:</tt> header.
   # * <tt>cc</tt> - Takes one or more email addresses. These addresses will receive a carbon copy of your email. Sets the <tt>Cc:</tt> header.
   # * <tt>bcc</tt> - Takes one or more email address. These addresses will receive a blind carbon copy of your email. Sets the <tt>Bcc</tt> header.
+  # * <tt>sender</tt> - Takes just one email address.  This address will be used to envelope-from of SMTP and appear in <tt>Sender:</tt> header.
   # * <tt>sent_on</tt> - The date on which the message was sent. If not set, the header wil be set by the delivery agent.
   # * <tt>content_type</tt> - Specify the content type of the message. Defaults to <tt>text/plain</tt>.
   # * <tt>headers</tt> - Specify additional headers to be set for the message, e.g. <tt>headers 'X-Mail-Count' => 107370</tt>.
@@ -315,6 +316,9 @@
     # header will be set by the delivery agent.
     adv_attr_accessor :sent_on
     
+    # Specify the Sender address for the message
+    adv_attr_accessor :sender
+    
     # Specify the subject of the message.
     adv_attr_accessor :subject
     
@@ -513,6 +517,7 @@
         m.to, m.from = quote_any_address_if_necessary(charset, recipients, from)
         m.bcc = quote_address_if_necessary(bcc, charset) unless bcc.nil?
         m.cc  = quote_address_if_necessary(cc, charset) unless cc.nil?
+        m.sender = sender unless sender.nil?
 
         m.mime_version = mime_version unless mime_version.nil?
         m.date = sent_on.to_time rescue sent_on if sent_on
@@ -548,16 +553,19 @@
 
       def perform_delivery_smtp(mail)
         destinations = mail.destinations
+        sender = mail.sender(nil) || mail.from
         mail.ready_to_send
 
         Net::SMTP.start(smtp_settings[:address], smtp_settings[:port], smtp_settings[:domain], 
             smtp_settings[:user_name], smtp_settings[:password], smtp_settings[:authentication]) do |smtp|
-          smtp.sendmail(mail.encoded, mail.from, destinations)
+          smtp.sendmail(mail.encoded, sender, destinations)
         end
       end
 
       def perform_delivery_sendmail(mail)
-        IO.popen("#{sendmail_settings[:location]} #{sendmail_settings[:arguments]}","w+") do |sm|
+        arguments = sendmail_settings[:arguments].dup
+        arguments += " -f#{mail.sender(nil)}" if mail.sender(nil)
+        IO.popen("#{sendmail_settings[:location]} #{arguments}","w+") do |sm|
           sm.print(mail.encoded.gsub(/\r/, ''))
           sm.flush
         end

2007年3月16日

Ruby 1.8.6 & Rails 1.2.3

気がつけば、Ruby 1.8.6がリリースされていました。 で、それと併せてRailsも1.2.3がリリースされたようです。

2007年11月10日

i18n_template_selector

あ、そういえばRails 1.2.5が出てる、というか、2.0 Previewなんてのも出てるや。

最近はめっきりRailsでコードを書くことも少なくなったので2.0ではどうなのかよくわからないんですけど、少なくとも1.2.5は国際化されてません。当然それでは困る人たちがいっぱい居るので、I18Nプラグインがあちこちで雨後の竹の子のように開発されてたと記憶しています。記憶していますというのは、今の状況がよくわからないので…ひょっとして淘汰されてde-factoがあるのかもしれないし。

まあそんなことはお構いなしってことで、いつだったか、自分でI18Nプラグインを書きました。というのは、雨後の竹の子のほとんどがgettextを使ったものだったんですが、MVCにgettextはそぐわないと個人的に思っていたもので。なぜかっちゅうのは以下のURLをみてもらいたいのですが。

でまあ、WebにもRoRにも国際化にも特に深い造詣があるわけではない(とか云うと一部で怒られそうですが、まじでそうなので)ので、個人的に使うだけで表には出していなかったのです。が、まあひょっとすると需要があるかもしれないし、一応出してみるかってことで、公開しました

繰り返しになりますが、WebにもRoRにも国際化にも別段詳しいわけではないので、はぁ?な実装かもしれませんが、それでも使ってみるよって奇特なかたはどうぞお使いください。不具合はご連絡いただけると、ひょっとして対応するかもしれません。

ちなみに、de-factができまくってるAuthentication周りの仕組みと、あと、Authorizationの仕組みもあったりするので、ぼちぼち公開していきます。