Posterous theme by Cory Watilo

Filed under: RoR

Canceling mail delivery from within mailer

In project I’m working on mail notifications are handled by resque_mailer, and are sent from models in after_create callback. When you call deliver – actually you are calling it on Resque::Mailer::Rails3MailerProxy – it puts mailer class name and arguments into the queue. Argument in our case is id of some stored event, for which user should be notified. Then background worker takes this data from queue, creates mailer, and calls

@mailer_class.send(:new, @action, *@args).message.deliver

And usually this isn’t bad.

But now we are creating records within DB transaction. Under some circumstances transaction could be rolled back. Oh wait! after_create doesn’t know anything about it, and it queues mail notification with object’s id… which isn’t available anymore!

The problem is – how to abort mail delivery from within mailer?

First thing you’d try is return false from mailer action. But mailer will anyway render template, and you’ll get the error.

I didn’t find any solution, so I dug in the mailer code and came with simple wrappers.

First, deliver is actually called on Mail::Message object. In case of error you should replace it with some dummy:

module BulletproofMailer
  class BlackholeMailMessage < Mail::Message
    def self.deliver
      false
    end
  end
end

Ok, but how to feed it into mailer? Here comes another wrapper where we are replacing self.message:

module BulletproofMailer
  class AbortDeliveryError < StandardError
  end

  class Base < ActionMailer::Base

    def abort_delivery
      raise AbortDeliveryError
    end

    def process(*args)
      begin
        super *args
      rescue AbortDeliveryError
        self.message = BulletproofMailer::BlackholeMailMessage
      end
    end
  end
end

Using these wrapper mailer would look like this:

class EventMailer < BulletproofMailer::Base
  include Resque::Mailer
  def event_created(event_id)
    begin
      @event = CalendarEvent.find(event_id)
    rescue ActiveRecord::RecordNotFound
      abort_delivery
    end
  end
end

PS: Yeah, I know we should rewrite mail callbacks, and we will do it. But a bit later.

Bzr rocks

С первого знакомства мне очень понравился bazaar-ng. И вот почему. Он нацелен на usability. И это видно сразу. Вот наверняка многие пользовались TortoiseSVN. Там все делается просто, легко и удобно, правда? А вот теперь пойдем в консоль удаленного сервера. И добавим маски для игнорирования файлов (логи, темпы, кеши всякие). А теперь еще добавим в репозитарий те два десятка сорсов в разных папках, которые написали/докопировали в проект. Все svn это не проблематично, но несколько неудобно. В bzr же все это делается легким движением руки - правим .bzrignore в корне проекта добавляя маски, потом жмем bzr add && bzr commit. Bzr ориентирован на ветки. И у меня получается ветка == проект. Я выгружаю себе его целиком. В результате в каждой папке нету папок .svn, есть лишь одна папка .bzr в корне проекта. Мне очень редко требовалось делать чекаут определенной папки из проекта. Проект часто требуется обновить до того, что живет в репозитории. Bzr имеет т.н. легковесные чекауты, которые не содержат подробной истории изменений. Как-раз то, что чаще всего нужно на рабочем сервере. Также весьма порадовала только-что сложившаяся ситуация: я делал commit, и внезапно пропал линк. bzr стоял и терпеливо ждал, пока я ребутнул модем. Как только пинги появились, он все быстро завершил. Ни обрывов, ни страшных ругательств небыло. Что касается скорости работы - она вполне приемлема. Да, есть системы и быстрее, но bzr меня вполне устраивает. Кроме того, мне абсолютно неважно, будет коммит выполняться 5 или 10 секунд, или даже 20 - я же не собираюсь безостановочно коммитить. Навеяно впечатлениями о Git.

ruby directory listing

Делая первые шаги в руби и рельсах наткнулся на необходимость получить листинг папки без "." и "..". Вот так реализовалось: [cc lang="ruby"] class Dir def self.listing(path, &block) return nil if path.nil? entries = Dir.entries(path).reject! { |filename| filename=='.' or filename=='..'} entries.each(&block) if block_given? entries end end [/cc] Огромаднейшее спасибо kpumuk'у за подсказки и помощь нюбу =)

rails got the power

Работаю сейчас над проектом. И вот для публикации надо сделать
  • кол-во просмотров
  • теги
  • рейтинги
  • комментарии
Начал писать на рельсах. И обнаружил Только кол-во просмотров надо писать самому. Сильно впечатлился.

NetBeans 6.0 released

Наконец-то вышел NetBeans 6.0 - замечательная Java IDE. Для меня она ценна изумительной поддержкой Ruby, а также наличием в плагинах средств для работы с UML, PHP, C/C++.
Media_httpblogssuncom_elwci