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 endWe 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.
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 ...
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 endThe 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 endA 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 endAs 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!
