Permalink
Browse files

Initial submission of load_model to the glomp open source repository

  • Loading branch information...
0 parents commit f073c16286e1e92c899e7d71107a1b70f1b5295f Justin Knowlden committed Jan 5, 2008
@@ -0,0 +1,24 @@
+MIT License
+--------------------------------------------------------------------------------
+Copyright (c) 2007 Justin Knowlden
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,4 @@
+LoadModel
+=========
+
+Description goes here
@@ -0,0 +1,22 @@
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+desc 'Default: run unit tests.'
+task :default => :test
+
+desc 'Test the load_model plugin.'
+Rake::TestTask.new(:test) do |t|
+ t.libs << 'lib'
+ t.pattern = 'test/**/*_test.rb'
+ t.verbose = true
+end
+
+desc 'Generate documentation for the load_model plugin.'
+Rake::RDocTask.new(:rdoc) do |rdoc|
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = 'LoadModel'
+ rdoc.options << '--line-numbers' << '--inline-source'
+ rdoc.rdoc_files.include('README')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
@@ -0,0 +1,2 @@
+class ApplicationController < ActionController::Base
+end
@@ -0,0 +1,46 @@
+# Don't change this file. Configuration is done in config/environment.rb and config/environments/*.rb
+
+unless defined?(RAILS_ROOT)
+ root_path = File.join(File.dirname(__FILE__), '..')
+
+ unless RUBY_PLATFORM =~ /mswin32/
+ require 'pathname'
+ root_path = Pathname.new(root_path).cleanpath(true).to_s
+ end
+
+ RAILS_ROOT = root_path
+end
+
+unless defined?(Rails::Initializer)
+ if File.directory?("#{RAILS_ROOT}/vendor/rails")
+ require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
+ else
+ require 'rubygems'
+
+ environment_without_comments = IO.readlines(File.dirname(__FILE__) + '/environment.rb').reject { |l| l =~ /^#/ }.join
+ environment_without_comments =~ /[^#]RAILS_GEM_VERSION = '([\d.]+)'/
+ rails_gem_version = $1
+
+ if version = defined?(RAILS_GEM_VERSION) ? RAILS_GEM_VERSION : rails_gem_version
+ # Asking for 1.1.6 will give you 1.1.6.5206, if available -- makes it easier to use beta gems
+ rails_gem = Gem.cache.search('rails', "~>#{version}.0").sort_by { |g|
+ g.version.version }.last
+
+ if rails_gem
+ gem "rails", "=#{rails_gem.version.version}"
+ require rails_gem.full_gem_path + '/lib/initializer'
+ else
+ STDERR.puts %(Cannot find gem for Rails ~>#{version}.0:
+ Install the missing gem with 'gem install -v=#{version} rails', or
+ change environment.rb to define RAILS_GEM_VERSION with your desired version.
+ )
+ exit 1
+ end
+ else
+ gem "rails"
+ require 'initializer'
+ end
+ end
+
+ Rails::Initializer.run(:set_load_path)
+end
@@ -0,0 +1,15 @@
+# Rename whichever definition you want to 'test'
+test:
+ :adapter: postgresql
+ :host: localhost
+ :database: load_model_test
+ :min_messages: ERROR
+# sqlite3:
+# :adapter: sqlite3
+# :dbfile: load_model.sqlite3.db
+# mysql:
+# :adapter: mysql
+# :host: localhost
+# :username: rails
+# :password:
+# :database: load_model_test
@@ -0,0 +1,62 @@
+# Be sure to restart your web server when you modify this file.
+
+# Uncomment below to force Rails into production mode when
+# you don't control web/app server and can't set it the proper way
+# ENV['RAILS_ENV'] ||= 'production'
+
+# Specifies gem version of Rails to use when vendor/rails is not present
+RAILS_GEM_VERSION = '1.2.6' unless defined? RAILS_GEM_VERSION
+
+# Bootstrap the Rails environment, frameworks, and default configuration
+require File.join(File.dirname(__FILE__), 'boot')
+
+Rails::Initializer.run do |config|
+ # Settings in config/environments/* take precedence over those specified here
+
+ # Skip frameworks you're not going to use (only works if using vendor/rails)
+ # config.frameworks -= [ :action_web_service, :action_mailer ]
+
+ # Only load the plugins named here, by default all plugins in vendor/plugins are loaded
+ # config.plugins = %W( exception_notification ssl_requirement )
+
+ # Add additional load paths for your own custom dirs
+ # config.load_paths += %W( #{RAILS_ROOT}/extras )
+
+ # Force all environments to use the same logger level
+ # (by default production uses :info, the others :debug)
+ # config.log_level = :debug
+
+ # Use the database for sessions instead of the file system
+ # (create the session table with 'rake db:sessions:create')
+ # config.action_controller.session_store = :active_record_store
+
+ # Use SQL instead of Active Record's schema dumper when creating the test database.
+ # This is necessary if your schema can't be completely dumped by the schema dumper,
+ # like if you have constraints or database-specific column types
+ # config.active_record.schema_format = :sql
+
+ # Activate observers that should always be running
+ # config.active_record.observers = :cacher, :garbage_collector
+
+ # Make Active Record use UTC-base instead of local time
+ # config.active_record.default_timezone = :utc
+
+ # See Rails::Configuration for more options
+end
+
+# Add new inflection rules using the following format
+# (all these examples are active by default):
+# Inflector.inflections do |inflect|
+# inflect.plural /^(ox)$/i, '\1en'
+# inflect.singular /^(ox)en/i, '\1'
+# inflect.irregular 'person', 'people'
+# inflect.uncountable %w( fish sheep )
+# end
+
+# Add new mime types for use in respond_to blocks:
+# Mime::Type.register "text/richtext", :rtf
+# Mime::Type.register "application/x-mobile", :mobile
+
+# Include your application configuration below
+require File.expand_path(File.join(File.dirname(__FILE__), '..', 'init'))
+require 'ruby-debug'
@@ -0,0 +1,19 @@
+# Settings specified here will take precedence over those in config/environment.rb
+
+# The test environment is used exclusively to run your application's
+# test suite. You never need to work with it otherwise. Remember that
+# your test database is "scratch space" for the test suite and is wiped
+# and recreated between test runs. Don't rely on the data there!
+config.cache_classes = true
+
+# Log error messages when you accidentally call methods on nil.
+config.whiny_nils = true
+
+# Show full error reports and disable caching
+config.action_controller.consider_all_requests_local = true
+config.action_controller.perform_caching = false
+
+# Tell ActionMailer not to deliver emails to the real world.
+# The :test delivery method accumulates sent emails in the
+# ActionMailer::Base.deliveries array.
+config.action_mailer.delivery_method = :test
@@ -0,0 +1,5 @@
+ActionController::Routing::Routes.draw do |map|
+ map.connect ':controller/service.wsdl', :action => 'wsdl'
+ map.connect ':controller/:action/:id.:format'
+ map.connect ':controller/:action/:id'
+end
@@ -0,0 +1,15 @@
+ActiveRecord::Schema.define(:version => 1) do
+ create_table 'users', :force => true do |t|
+ t.column :name, :string
+ end
+
+ create_table 'alternates', :force => true do |t|
+ t.column :alternate_id, :integer
+ t.column :name, :string
+ end
+
+ create_table 'fuzzles', :force => true do |t|
+ t.column :fuzzle_id, :integer
+ t.column :name, :string
+ end
+end
@@ -0,0 +1,3 @@
+require 'load_model'
+
+ActionController::Base.send(:include, Glomp::LoadModel)
@@ -0,0 +1 @@
+# Install hook code here
@@ -0,0 +1,147 @@
+# LoadModel
+module Glomp #:nodoc:
+ module LoadModel #:nodoc
+
+ class RequiredRecordNotFound < Exception; end
+
+ def self.included(klass)
+ klass.extend(ClassMethods)
+ end
+
+ module ClassMethods #:nodoc
+ # Loads an instance matching the model name with the result of searching
+ # for an object against a model defined by the provided model name. The
+ # parameter :id will be used by default. load_model will also require that
+ # the value of the id be an integer.
+ #
+ # Example
+ # load_model :silly_fellow
+ # def action
+ # @silly_fellow.do_something
+ # end
+ #
+ # You can also require that a model instance be found for all actions or
+ # given actions. Default behavior is to not require that a model instance
+ # be found. When require is on and a record is not found, the
+ # RequiredRecordNotFound Exception is thrown.
+ #
+ # To require for all actions, simply pass _true_ to <em>:require</em>
+ #
+ # Example
+ # load_model :silly_fellow, :require => true
+ #
+ # To require for specific actions, pass an array of action names to
+ # <em>:require</em>. The model will be loaded for all actions, regardless
+ # of whether or not required is provided.
+ #
+ # Example
+ # load_model :silly_fellow, :require => [:show, :update]
+ #
+ # To use a different parameter key and Model than the default, you can
+ # provide the values in the :paramater_key and :class options, like the
+ # following:
+ #
+ # Example
+ # load_model :foo, :class => :user, :parameter_key => :bar_id
+ #
+ # In the above example, _load_model_ will assume the parameter_key and the
+ # model's lookup key are both the same. For instance, the above example
+ # would result in a call like the following:
+ #
+ # @foo = User.find_by_bar_id(params[:bar_id])
+ #
+ # However, if you want to use a different lookup key, you can also provide
+ # that key name using the :foreign_key parameter; like so:
+ #
+ # Example
+ # load_model :foo, :class => :user, :parameter_key => :bar_id,
+ # :foreign_key => :id
+ #
+ # Which would result in a call similar to the following:
+ #
+ # @foo = User.find_by_id(params[:bar_id])
+ #
+ # If you want to only use load_model for some actions, you can still name
+ # them as you would with a before_filter using :only or :except. If you
+ # provide an :only and an :except value. :only will always win out over
+ # :except when there are collisions (i.e. you provide both in the same
+ # call)
+ #
+ # Example
+ # load_model :foo, :only => [:show]
+ # load_model :bar, :except => [:create]
+ #
+ def load_model(name, opts={})
+ unless loaders
+ self.class_eval do
+ before_filter :glomp_load_model_runner
+ end
+ write_inheritable_attribute(:loaders, [])
+ end
+ loaders << ModelLoader.new(name, opts)
+ end
+
+ def loaders
+ self.read_inheritable_attribute(:loaders)
+ end
+
+ class ModelLoader #:nodoc
+ def initialize(name, opts={})
+ config = {:require => false, :parameter_key => :id,
+ :class => name}.merge(opts)
+ config[:foreign_key] ||= config[:parameter_key]
+ @ivar = "@#{name}".to_sym
+ @klass = config[:class].to_s.classify.constantize
+ @param_key = config[:parameter_key].to_s
+ @foreign_key = config[:foreign_key].to_s
+ @requires = parse_required_actions(config[:require])
+ @except = opts[:except].to_a.map{|a| a.to_s}
+ @only = opts[:only].to_a.map{|a| a.to_s} #- @except
+ end
+
+ def process(controller)
+ action = action_name(controller)
+ if processable?(action)
+ key_value = controller.params[@param_key.to_sym]
+ obj = nil
+ if key_value.to_s =~ /^[0-9]+$/
+ obj = @klass.send("find_by_#{@foreign_key}".to_sym, key_value)
+ controller.instance_variable_set(@ivar, obj)
+ end
+ if required?(action) && obj.nil?
+ raise RequiredRecordNotFound
+ end
+ end
+ end
+ private
+ def parse_required_actions(requires)
+ requires = nil if requires == false
+ requires = requires.to_a.map {|a| a.to_s} unless requires == true
+ requires
+ end
+
+ def action_name(controller)
+ controller.action_name
+ end
+
+ def processable?(action)
+ processable = !@except.include?(action)
+ processable = @only.include?(action) unless @only.empty?
+ processable
+ end
+
+ def required?(action)
+ @requires == true || @requires.include?(action)
+ end
+ end # ModelLoader
+
+ end # ClassMethods
+
+ private
+
+ def glomp_load_model_runner
+ self.class.loaders.each { |loader| loader.process(self) }
+ end
+
+ end # LoadModel
+end # Glomp
@@ -0,0 +1,4 @@
+# desc "Explaining what the task does"
+# task :load_model do
+# # Task goes here
+# end
Oops, something went wrong.

0 comments on commit f073c16

Please sign in to comment.