Opensteam_blog_logo4
opensteam.net | rss | search | archive
Results (escape to close):

check active ActionMailer

Posted by michael.schaerfer on 10-Nov-08 at 19:01

In the openSteam backend, we wanted to give the admins the possibility to manually activate or deactivate mailer, like order-confirmation or user-signup mails.

We built a model, called SystemMailer, which holds the mailer classname, the mailer method and a boolean.

Migration File:

   1  class CreateSystemMailer < ActiveRecord::Migration
   2    def self.up
   3      create_table :system_mailers do |t|
   4        t.string :mailer_method
   5        t.string :mailer_class
   6        t.boolean :active
   7  
   8        t.timestamps
   9      end
  10    end
  11  
  12    def self.down
  13      drop_table :system_mailers
  14    end
  15  end

Model:

   1  class SystemMailer < ActiveRecord::Base
   2    def active? ; self.active ; end#
   3    named_scope :active, { :conditions => { :active => true } }
   4  end

Then we built an alias method chain for the ActionMailer::Base#deliver! method, to check whether the current mail-method of the current mailer is active:

   1  class ActionMailer::Base
   2  
   3    def deliver_with_active_mailer_check!(mail)
   4      active_mailer = SystemMailer.find( :all,
   5        :conditions => { 
   6          :mailer_class => self.class.to_s,
   7          :mailer_method => @template,
   8          :active => true } )
   9  
  10      return nil if active_mailer.empty?
  11  
  12      deliver_without_active_mailer_check!( mail )
  13    end
  14  
  15    alias_method_chain :deliver!, :active_mailer_check
  16  
  17  end

In this alias-method, we try to fetch an active SystemMailer entry (with the current class and method name). If the results are empty (no active SystemMailer found), we return nil, otherwise we call the original deliver! method. Pretty simple.

v0.9.3 released!

Posted by michael.schaerfer on 01-Oct-08 at 17:46

We finally released a new version of openSteam today.

This release introduces some major enhancements of the checkout- and order-process, like shipping-rate calculation, tax management and an ActiveMerchant integration for credit-card payments.

New Features:

  • Taxes: define taxes or tax-groups for products and regions
  • ActiveMerchant integration
  • PaymentMethods: use implemented payment-methods or implement your own
  • ShippingRate: define rates for products, regions and payment-types.
  • PDF-Export for invoices (using the excellent prawnto plugin)

For a full list of changes please read the CHANGELOG, and if you're curious what to expect in future releases, please visit the Roadmap at our homepage.

In future posts we will try to describe some of the new features and their implementations in detail.

form_tag block in a helper-method

Posted by michael.schaerfer on 24-Jul-08 at 07:45


According to this Ticket, using form_tag with a block in a helper-method is broken in rails 2.1.

Here is a, not so elegant but working, solution:
   1  def render_form_tag_in_helper( _erbout, url, *args )
   2    form_tag( url ) do
   3      concat( submit_tag("button"), binding )
   4    end
   5  end
We have to pass the _erbout-variable to the helper-method in order to make the form_tag-method work. And to add elements to the form (submit_buttons, text_fields, etc), we have to call concat (to add the elements to the _erbout variable) with the current binding.
Comments: 0 (view/add your own) Tags: code

Column/Attribute names for a model

Posted by michael.schaerfer on 23-Jul-08 at 20:06

A quick way to get all column/attribute names for a model: (normal columns are Strings, association-attributes are Symbols)

   1  # returns all columns/attributes for a model
   2  # column-names used for associations (foreign_keys) are replaces by their
   3  # association-names (as symbol).
   4  def get_column_names_for( record )
   5    # get all column-names, check for foreign_keys and replace them by association_name
   6    record.columns.collect(&:name).collect { |c|
   7        (a = check_association( record, c ) ).empty? ? c : a.collect(&:name)
   8    }.flatten.uniq + 
   9    # get all has_one/has_many/habtm association names
  10    record.reflect_on_all_associations.select { |a| a.macro.to_s =~/^has/ }.collect(&:name)
  11  
  12  end
  13    
  14    
  15  def check_association( record, string )
  16    # check if +string+ (like "artist_id") is a foreign_key for an association
  17    # if yes, return association.
  18    record.reflect_on_all_associations.select { |a| a.options[:foreign_key] ? 
  19      a.options[:foreign_key].to_sym == string.to_sym : 
  20      a.name.to_s.foreign_key.to_sym == string.to_sym }
  21  end

Useful if you want to build like an automatic scaffold function or ...

Comments: 0 (view/add your own) Tags: code

State-Pattern using Modules

Posted by michael.schaerfer on 22-Jul-08 at 21:20


In the last weeks, we tried to implement a state-pattern for our orders, simply put: different states means different functionality.
We tried various approaches, like simple state-symbols, state-classes (to hold the state-specifc methods and return new states), state-associations and the very nice AASM plugin by Scott Barron.
But all this techniques felt very clumsy for our simple needs and not so ... 'ruby-like'.

Then i stumbled across Jay Fields Post and really liked the approach of using just state-modules and delegating to the instance_method ('cause all modules included in a class are just ancestors of this class!).

Here a brief overview of our solution:
   1  # the order-class
   2  class Order
   3    include StateLogic
   4  
   5    #states
   6    include Finished
   7    attr_accessor :state
   8  end
The StateLogic Module (defines the 'fire_event' method to delegate to the state-module).
   1  module StateLogic
   2    def fire_event(name, *args, &block)
   3      state_module = self.state.classify.constantize
   4      
   5      if state_module.instance_methods(false).include?(name)
   6        state_module.instance_method(m).bind( self ).call( *args, &block )
   7      else
   8        puts "event '#{name}' not defined for state '#{state}'"
   9        return false
  10      end
  11    end
  12  end
A State-Module
   1  module Finished
   2    def self.included(base)
   3      self.instance_methods(false).each do |m|
   4        base.class_eval do
   5          define_method(m) { |*args| fire_event(m,*args) }
   6        end
   7      end
   8    end
   9  
  10    #an event
  11    def say_something
  12      puts "now in state '#{state}'"
  13    end
  14  
  15  end    
As you can see, we override every state-module instance_method in the receiver-class to call the fire_event method. And in this method, we check if the current state-module defines such an instance_method, bind it to the order-instance and call it (or printing an error message, if no such method is defined in the current state-module.)
Pretty simple!