# railsext.rb - my collection of rails hacks # # force const_missing to preload these classes - muckery # ActionController ActionController::Base ActiveRecord ActiveRecord::Base # support for using helper methods in controllers/models # class Helper < ActionView::Base def Helper.list ActionView::Helpers.constants.grep(/Helper/i).map do |const| ActionView::Helpers.const_get(const) end end attr_accessor 'controller' def initialize controller = ( ActionController.current || ApplicationController.new ), *modules @controller = controller modules.push nil if modules.empty? modules.flatten.each do |mod| case mod when NilClass, :all, 'all' Helper.list.each{|helper| extend helper} when Module extend mod when Symbol, String mod = mod.to_s.underscore.sub(/helper$/, '') Helper.list.each do |helper| if mod == helper.name.underscore.sub(/helper$/, '') extend helper end end when Regexp Helper.list.each do |helper| if helper.name =~ mod extend helper end end else raise ArgumentError, mod.class.name end end extend @controller.master_helper_module if @controller end def session controller.session end end module ActionController class << self attr_accessor 'current' end end class ActionController::Base before_filter :setup_current_controller after_filter :teardown_current_controller protected def setup_current_controller ::ActionController.current = self end def teardown_current_controller ::ActionController.current = nil end def helper &block @helper = Helper.new(::ActionController.current || self) block ? @helper.instance_eval(&block) : @helper end def self.helper_import *methods methods.flatten.compact.each do |method| code = <<-code def #{ method } *a, &b helper{ #{ method }(*a, &b) } end protected '#{ method }' code eval code end end end class ActiveRecord::Base def helper &block helper = Helper.new(::ActionController.current || ::ActionController::Base.new) block ? helper.instance_eval(&block) : helper end end # support for immediate (throw/catch) base rendering methods # class ActionController::Base protected def render! *a, &b render *a, &b unless a.empty? and b.nil? throw :render, self end def redirect_to! *a, &b redirect_to *a, &b ensure render! end def redirect_to_url! *a, &b redirect_to_url *a, &b ensure render! end def not_found! options = {} options = {:inline => options} if String == options options.to_options! unless options.has_key?(:inline) or options.has_key?(:text) options[:inline] = <<-html

Sorry, but we could not find the page you are looking for.

#{ h helper.url_for(request.request_uri) }

html end options[:status] ||= 404 options[:layout] ||= 'application' unless options[:layout] == false render! options end def perform_action_without_filters if self.class.action_methods.include?(action_name) catch(:render){ send(action_name) } render unless performed? elsif respond_to? :method_missing catch(:render){ send(:method_missing, action_name) } render unless performed? elsif template_exists? && template_public? render else raise ::ActionController::UnknownAction, "No action responded to #{action_name}", caller end end end # generic error classes used for model level application errors # class ActiveRecord::Base class Error < ::ActiveRecord::ActiveRecordError; end class RecordNotFound < ::ActiveRecord::RecordNotFound; end end # support for logging to the rails log from anywhere in the codebase # class Object def log(*a, &b) logger = RAILS_DEFAULT_LOGGER if a.empty? and b.nil? logger else logger.info(*a, &b) end end end # support for conditional excution based on rails_env # class Object %w( test development production training ).each do |rails_env| module_eval <<-code def #{ rails_env }? &block if defined?(RAILS_ENV) and RAILS_ENV == '#{ rails_env }' return( block ? block.call : true ) end return false end code end def stage? &block if defined?(RAILS_STAGE) and RAILS_STAGE return( block ? block.call : true ) end return false end end # support for executing sql on the raw connection, getting back an array of # results # class Object def db(*a, &b) connection = ActiveRecord::Base.connection.raw_connection return connection if a.empty? and b.nil? adapter = ActiveRecord::Base.configurations[ RAILS_ENV ][ 'adapter' ].to_s case adapter when 'oci', 'oracle' cursor = connection.exec *a if b while row = cursor.fetch; b.call row end else returning [] do |rows| while row = cursor.fetch rows << row end end end when 'mysql', 'postgresql', 'sqlite' if b connection.query(*a).each do |row| b.call row end else returning [] do |rows| connection.query(*a).each do |row| rows << row end end end else raise ArgumentError, "#{ adapter } not implemented yet" end end end # support for class level declarations of ActiveRecord default values for # *new* records # class ActiveRecord::Base class << self def defaults *argv, &block const_set(:Defaults, []) unless const_defined?(:Defaults) defaults = const_get(:Defaults) options = if block argv.flatten.inject({}){|h,k| h.update k => block} else case argv.size when 2 { argv.first => argv.last } else argv.inject({}){|h,x| h.update x.to_hash} end end options.to_options! unless options.empty? options.each{|k,v| defaults << [k,v]} add_after_initialize_with_defaults! defaults end defaults end alias_method :default, :defaults def add_after_initialize_with_defaults! defaults = {} return if defined?(@add_after_initialize_with_defaults) after_initialize = instance_method(:after_initialize) rescue nil define_method(:after_initialize) do |*args| this = self after_initialize.bind(self).call(*args) if after_initialize return unless new_record? defaults.each do |key, value| value = instance_eval(&value) if value.respond_to?(:to_proc) write_attribute key, value end end ensure @add_after_initialize_with_defaults = true unless $! end end end # support for indexing operator # class ActiveRecord::Base def self.[](*args, &block) find(*args, &block) end end # support for using named routes from the console - mega hack # def use_named_routes! options = {} include ActionController::UrlWriter options.to_options! options.reverse_merge! :host => 'localhost', :port => 3000 default_url_options.reverse_merge!(options) end # top level methods to hook into above # module Kernel private def transaction(*a, &b) ActiveRecord::Base.transaction(*a, &b) end def rollback! raise ActiveRecord::Rollback end def helper &block helper = Helper.new(::ActionController.current || ::ActionController::Base.new) block ? helper.instance_eval(&block) : helper end end