thumblemonks-load_model 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/HISTORY.markdown ADDED
@@ -0,0 +1,4 @@
1
+ ## v0.1
2
+
3
+ * Turned load_model from a plugin into a gem
4
+ * Moved all rails test support code into a rails sub-dir
data/MIT-LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ MIT License
2
+ --------------------------------------------------------------------------------
3
+ Copyright (c) 2007 Thumble Monks, Justin Knowlden
4
+
5
+ Permission is hereby granted, free of charge, to any person
6
+ obtaining a copy of this software and associated documentation
7
+ files (the "Software"), to deal in the Software without
8
+ restriction, including without limitation the rights to use,
9
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the
11
+ Software is furnished to do so, subject to the following
12
+ conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24
+ OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,102 @@
1
+ # Load Model
2
+
3
+ A glorified before_filter that loads an instance of an `ActiveRecord` object as the result of searching for said object against a model defined by a given model name. The value of the HTTP request parameter `:id` will be used as the default lookup value. `LoadModel` will give you the ability to require an instance be found and/or override several other default behaviors.
4
+
5
+ Example
6
+
7
+ class SillyFellowController < Application
8
+ load_model :silly_fellow
9
+ def action
10
+ @silly_fellow.do_something
11
+ end
12
+ end
13
+
14
+ You can 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, a `ThumbleMonks::RequiredRecordNotFound` Exception is thrown; which extends from ActiveRecord::RecordNotFound, for your convenience.
15
+
16
+ To turn require on for all actions, simply pass *true* to a provided `:require` attribute, like so:
17
+
18
+ Example
19
+
20
+ load_model :silly_fellow, :require => true
21
+
22
+ To turn require on for specific actions, pass an array of action names to `:require`. The model will be loaded for all actions, regardless of whether or not required is provided, but the exception will only be raised when an record is not found for the provided actions.
23
+
24
+ Example
25
+
26
+ load_model :silly_fellow, :require => [:show, :update]
27
+
28
+ To use a different parameter key and model than the default, you can provide the values in the `:paramater_key` and `:class` options (though not necessary to provide them together), like the following:
29
+
30
+ Example
31
+
32
+ load_model :foo, :class => :user, :parameter_key => :bar_id
33
+
34
+ In the above example, `load_model` will assume the parameter_key and the model's primary/foreign key are both the same. For instance, the above example would result in a call like the following:
35
+
36
+ @foo = User.find_by_bar_id(params[:bar_id])
37
+
38
+ If you want to use a different lookup/foreign key than the default, you can also provide that key name using the `:foreign_key` parameter; like so:
39
+
40
+ Example
41
+
42
+ load_model :foo, :class => :user, :parameter_key => :bar_id,
43
+ :foreign_key => :baz_id
44
+
45
+ Which would result in a call similar to the following:
46
+
47
+ @foo = User.find_by_baz_id(params[:bar_id])
48
+
49
+ 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)
50
+
51
+ Example
52
+
53
+ load_model :foo, :only => [:show]
54
+ load_model :bar, :except => [:create]
55
+
56
+ Finally, load_model supports a :through option. With :through, you can load a model via the association of an existing loaded model. This is especially useful for RESTful controllers.
57
+
58
+ Example
59
+
60
+ load_model :user, :require => true, :parameter_key => :user_id
61
+ load_model :post, :through => :user
62
+
63
+ In this example, a @post record will be loaded through the @user record with essentially the following code:
64
+
65
+ @user.posts.find_by_id(params[:id])
66
+
67
+ All of the previously mentioned options still apply (:parameter_key, :foreign_key, :require, :only, and :except) except for the :class option. Meaning you could really mess around!
68
+
69
+ Example
70
+
71
+ load_model :user, :require => true, :parameter_key => :user_id
72
+ load_model :post, :through => :person, :parameter_key => :foo_id,
73
+ :foreign_key => :baz_id
74
+
75
+ Would result in a call similar to the following:
76
+
77
+ @person.posts.find_by_baz_id(params[:foo_id])
78
+
79
+ Require works as you would expect.
80
+
81
+ The only current caveat is that load_model assumes a has_many association exists on the :through model and is named in the pluralized form. In essence, in the above example, there is no way to tell load_model not look for the "posts" association. Perhaps a future change.
82
+
83
+ ## Installation
84
+
85
+ sudo gem install thumblemonks-load_model
86
+
87
+ ## Requirements
88
+
89
+ 1. Ruby 1.8.6 or higher
90
+ 2. Rails 2.x or higher
91
+
92
+ ## Acknowledgements
93
+
94
+ Anyone who developed, discussed, or any other way participated in HTTP, REST, and Rails.
95
+
96
+ ## Contact
97
+
98
+ Justin Knowlden <gus@gusg.us>
99
+
100
+ ## License
101
+
102
+ See MIT-LICENSE
data/Rakefile ADDED
@@ -0,0 +1,22 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the load_model plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.pattern = 'test/**/*_test.rb'
12
+ t.verbose = true
13
+ end
14
+
15
+ desc 'Generate documentation for the load_model plugin.'
16
+ Rake::RDocTask.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = 'rdoc'
18
+ rdoc.title = 'LoadModel'
19
+ rdoc.options << '--line-numbers' << '--inline-source'
20
+ rdoc.rdoc_files.include('README')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ end
data/lib/load_model.rb ADDED
@@ -0,0 +1,202 @@
1
+ module ThumbleMonks #:nodoc:
2
+ module LoadModel
3
+
4
+ class RequiredRecordNotFound < ActiveRecord::RecordNotFound; end
5
+
6
+ def self.included(klass)
7
+ klass.extend(ClassMethods)
8
+ end
9
+
10
+ module ClassMethods #:nodoc
11
+ # A glorified before_filter that loads an instance of an ActiveRecord
12
+ # object as# the result of searching for said object against a model
13
+ # defined by a given model name. The value of the HTTP request parameter
14
+ # :id will be used as the default lookup value. LoadModel will give you
15
+ # the ability to require an instance be found and/or override several
16
+ # other default behaviors.
17
+ #
18
+ # Example
19
+ # class SillyFellowController < Application
20
+ # load_model :silly_fellow
21
+ # def action
22
+ # @silly_fellow.do_something
23
+ # end
24
+ # ens
25
+ #
26
+ # You can require that a model instance be found for all actions or given
27
+ # actions. Default behavior is to not require that a model instance be
28
+ # found. When require is on and a record is not found, a
29
+ # ThumbleMonks::RequiredRecordNotFound Exception is thrown; which does
30
+ # conveniently extend ActiveRecord::RecordNotFound.
31
+ #
32
+ # To turn require on for all actions, simply pass _true_ to a provided
33
+ # <em>:require</em> attribute, like so:
34
+ #
35
+ # Example
36
+ # load_model :silly_fellow, :require => true
37
+ #
38
+ # To turn require on for specific actions, pass an array of action names
39
+ # to <em>:require</em>. The model will be loaded for all actions,
40
+ # regardless of whether or not required is provided, but the exception
41
+ # will only be raised when an record is not found for the provided
42
+ # actions.
43
+ #
44
+ # Example
45
+ # load_model :silly_fellow, :require => [:show, :update]
46
+ #
47
+ # To use a different parameter key and model than the default, you can
48
+ # provide the values in the :paramater_key and :class options (though not
49
+ # necessary to provide them together), like the following:
50
+ #
51
+ # Example
52
+ # load_model :foo, :class => :user, :parameter_key => :bar_id
53
+ #
54
+ # In the above example, _load_model_ will assume the parameter_key is
55
+ # :bar_id while assuming the model's primary/foreign is still :id. For
56
+ # instance, the above example would result in a call like the following:
57
+ #
58
+ # @foo = User.find_by_id(params[:bar_id])
59
+ #
60
+ # If you want to use a different lookup/foreign key than the default, you
61
+ # can also provide that key name using the :foreign_key parameter; like
62
+ # so:
63
+ #
64
+ # Example
65
+ # load_model :foo, :class => :user, :parameter_key => :bar_id,
66
+ # :foreign_key => :baz_id
67
+ #
68
+ # Which would result in a call similar to the following:
69
+ #
70
+ # @foo = User.find_by_baz_id(params[:bar_id])
71
+ #
72
+ # If you want to only use load_model for some actions, you can still name
73
+ # them as you would with a before_filter using :only or :except. If you
74
+ # provide an :only and an :except value. :except will always win out over
75
+ # :only in the event of a collision.
76
+ #
77
+ # Example
78
+ # load_model :foo, :only => [:show]
79
+ # load_model :bar, :except => [:create]
80
+ #
81
+ # Finally, load_model supports a :through option. With :through, you can
82
+ # load a model via the association of an existing loaded model. This is
83
+ # especially useful for RESTful controllers.
84
+ #
85
+ # Example
86
+ # load_model :user, :require => true, :parameter_key => :user_id
87
+ # load_model :post, :through => :user
88
+ #
89
+ # In this example, a @post record will be loaded through the @user record
90
+ # with essentially the following code:
91
+ #
92
+ # @user.posts.find_by_id(params[:id])
93
+ #
94
+ # All of the previously mentioned options still apply (:parameter_key,
95
+ # :foreign_key, :require, :only, and :except) except for the :class
96
+ # option. Meaning you could really mess around!
97
+ #
98
+ # Example
99
+ # load_model :user, :require => true, :parameter_key => :user_id
100
+ # load_model :post, :through => :person, :parameter_key => :foo_id,
101
+ # :foreign_key => :baz_id
102
+ #
103
+ # Would result in a call similar to the following:
104
+ #
105
+ # @person.posts.find_by_baz_id(params[:foo_id])
106
+ #
107
+ # Require works as you would expect
108
+ #
109
+ # The only current caveat is that load_model assumes a has_many
110
+ # association exists on the :through model and is named in the pluralized
111
+ # form. In essence, in the above example, there is no way to tell
112
+ # load_model not look for the "posts" association. Perhaps a future
113
+ # change.
114
+ #
115
+ def load_model(name, opts={})
116
+ unless loaders
117
+ self.class_eval { before_filter :load_specified_models }
118
+ write_inheritable_attribute(:loaders, [])
119
+ end
120
+ loaders << (opts[:through] ? ThroughModelLoader : ModelLoader).new(name, opts)
121
+ end
122
+
123
+ def loaders; self.read_inheritable_attribute(:loaders); end
124
+
125
+ class ModelLoader #:nodoc
126
+ attr_reader :assigns_to, :load_through, :parameter_key, :foreign_key,
127
+ :except, :only, :requires
128
+
129
+ def initialize(name, opts={})
130
+ config = {:require => false, :parameter_key => :id,
131
+ :foreign_key => :id, :class => name}.merge(opts)
132
+ @assigns_to = "@#{name}".to_sym
133
+ @load_through = config[:class].to_s.classify.constantize
134
+ @parameter_key = config[:parameter_key].to_s
135
+ @foreign_key = config[:foreign_key].to_s
136
+ @requires = parse_required_actions(config[:require])
137
+ @except = stringify_array(config[:except])
138
+ @only = stringify_array(config[:only])
139
+ end
140
+
141
+ def action_allowed?(action)
142
+ return false if except.include?(action)
143
+ only.empty? ? true : only.include?(action)
144
+ end
145
+
146
+ def action_required?(action)
147
+ requires == true || requires.include?(action)
148
+ end
149
+
150
+ def load_model(controller)
151
+ begin
152
+ lookup = parameter_value(controller)
153
+ source(controller).send("find_by_#{foreign_key}", lookup)
154
+ rescue ActiveRecord::StatementInvalid
155
+ nil
156
+ end
157
+ end
158
+ private
159
+ def source(controller) load_through; end
160
+
161
+ def parse_required_actions(actions)
162
+ actions == true ? true : stringify_array(actions)
163
+ end
164
+
165
+ def parameter_value(controller) controller.params[parameter_key]; end
166
+
167
+ def stringify_array(value) Array(value).map(&:to_s); end
168
+ end # ModelLoader
169
+
170
+ class ThroughModelLoader < ModelLoader #:nodoc
171
+ attr_reader :load_through, :association
172
+ def initialize(name, opts={})
173
+ super(name, opts)
174
+ @load_through = "@#{opts[:through]}".to_sym
175
+ @association = opts[:association] || name.to_s.pluralize
176
+ end
177
+ private
178
+ def source(controller)
179
+ controller.instance_variable_get(load_through).send(association)
180
+ end
181
+ end # ThroughModelLoader
182
+
183
+ end # ClassMethods
184
+
185
+ private
186
+
187
+ def load_specified_models
188
+ self.class.loaders.each do |loader|
189
+ if loader.action_allowed?(action_name)
190
+ obj = loader.load_model(self)
191
+ if obj.nil? && loader.action_required?(action_name)
192
+ raise RequiredRecordNotFound
193
+ end
194
+ instance_variable_set(loader.assigns_to, obj)
195
+ end
196
+ end
197
+ end
198
+
199
+ end # LoadModel
200
+ end # ThumbleMonks
201
+
202
+ ActionController::Base.send(:include, ThumbleMonks::LoadModel)
@@ -0,0 +1,52 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "load_model"
3
+ s.version = "0.1.0"
4
+ s.date = "2009-01-03"
5
+ s.summary = "Rails Controller plugin that provides easy and useful macros for tying models and requests together"
6
+ s.email = %w[gus@gusg.us gabriel.gironda@gmail.com]
7
+ s.homepage = "http://github.com/thumblemonks/load_model"
8
+ s.description = "Rails Controller plugin that provides easy and useful macros for tying models and requests together"
9
+ s.authors = %w[Justin\ Knowlden Gabriel\ Gironda]
10
+
11
+ s.rubyforge_project = %q{load_model}
12
+
13
+ s.has_rdoc = true
14
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Load Model", "--main", "README.markdown"]
15
+ s.extra_rdoc_files = ["HISTORY.markdown", "README.markdown"]
16
+
17
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to?(:required_rubygems_version=)
18
+ s.rubygems_version = "1.3.1"
19
+ s.require_paths = ["lib"]
20
+
21
+ # run git ls-files to get an updated list
22
+ s.files = %w[
23
+ HISTORY.markdown
24
+ MIT-LICENSE
25
+ README.markdown
26
+ Rakefile
27
+ lib/load_model.rb
28
+ load_model.gemspec
29
+ ]
30
+
31
+ s.test_files = %w[
32
+ rails/app/controllers/application.rb
33
+ rails/config/boot.rb
34
+ rails/config/database.yml
35
+ rails/config/environment.rb
36
+ rails/config/environments/test.rb
37
+ rails/config/routes.rb
38
+ rails/db/schema.rb
39
+ rails/db/test.db
40
+ rails/log/test.log
41
+ test/functional/controller_helper.rb
42
+ test/functional/keys_controller_test.rb
43
+ test/functional/load_model_test.rb
44
+ test/functional/require_model_controller_test.rb
45
+ test/functional/restrict_options_controller_test.rb
46
+ test/functional/string_key_load_model_test.rb
47
+ test/functional/through_controller_test.rb
48
+ test/test_helper.rb
49
+ ]
50
+
51
+ s.post_install_message = %q{Choosy prima donnas choose Thumble Monks}
52
+ end
@@ -0,0 +1,2 @@
1
+ class ApplicationController < ActionController::Base
2
+ end
@@ -0,0 +1,109 @@
1
+ # Don't change this file!
2
+ # Configure your app in config/environment.rb and config/environments/*.rb
3
+
4
+ RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
5
+
6
+ module Rails
7
+ class << self
8
+ def boot!
9
+ unless booted?
10
+ preinitialize
11
+ pick_boot.run
12
+ end
13
+ end
14
+
15
+ def booted?
16
+ defined? Rails::Initializer
17
+ end
18
+
19
+ def pick_boot
20
+ (vendor_rails? ? VendorBoot : GemBoot).new
21
+ end
22
+
23
+ def vendor_rails?
24
+ File.exist?("#{RAILS_ROOT}/vendor/rails")
25
+ end
26
+
27
+ def preinitialize
28
+ load(preinitializer_path) if File.exist?(preinitializer_path)
29
+ end
30
+
31
+ def preinitializer_path
32
+ "#{RAILS_ROOT}/config/preinitializer.rb"
33
+ end
34
+ end
35
+
36
+ class Boot
37
+ def run
38
+ load_initializer
39
+ Rails::Initializer.run(:set_load_path)
40
+ end
41
+ end
42
+
43
+ class VendorBoot < Boot
44
+ def load_initializer
45
+ require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
46
+ Rails::Initializer.run(:install_gem_spec_stubs)
47
+ end
48
+ end
49
+
50
+ class GemBoot < Boot
51
+ def load_initializer
52
+ self.class.load_rubygems
53
+ load_rails_gem
54
+ require 'initializer'
55
+ end
56
+
57
+ def load_rails_gem
58
+ if version = self.class.gem_version
59
+ gem 'rails', version
60
+ else
61
+ gem 'rails'
62
+ end
63
+ rescue Gem::LoadError => load_error
64
+ $stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.)
65
+ exit 1
66
+ end
67
+
68
+ class << self
69
+ def rubygems_version
70
+ Gem::RubyGemsVersion if defined? Gem::RubyGemsVersion
71
+ end
72
+
73
+ def gem_version
74
+ if defined? RAILS_GEM_VERSION
75
+ RAILS_GEM_VERSION
76
+ elsif ENV.include?('RAILS_GEM_VERSION')
77
+ ENV['RAILS_GEM_VERSION']
78
+ else
79
+ parse_gem_version(read_environment_rb)
80
+ end
81
+ end
82
+
83
+ def load_rubygems
84
+ require 'rubygems'
85
+ min_version = '1.1.1'
86
+ unless rubygems_version >= min_version
87
+ $stderr.puts %Q(Rails requires RubyGems >= #{min_version} (you have #{rubygems_version}). Please `gem update --system` and try again.)
88
+ exit 1
89
+ end
90
+
91
+ rescue LoadError
92
+ $stderr.puts %Q(Rails requires RubyGems >= #{min_version}. Please install RubyGems and try again: http://rubygems.rubyforge.org)
93
+ exit 1
94
+ end
95
+
96
+ def parse_gem_version(text)
97
+ $1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*["']([!~<>=]*\s*[\d.]+)["']/
98
+ end
99
+
100
+ private
101
+ def read_environment_rb
102
+ File.read("#{RAILS_ROOT}/config/environment.rb")
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ # All that for this:
109
+ Rails.boot!
@@ -0,0 +1,3 @@
1
+ test:
2
+ :adapter: sqlite3
3
+ :dbfile: db/test.db
@@ -0,0 +1,71 @@
1
+ # Be sure to restart your server when you modify this file
2
+
3
+ # Uncomment below to force Rails into production mode when
4
+ # you don't control web/app server and can't set it the proper way
5
+ # ENV['RAILS_ENV'] ||= 'production'
6
+
7
+ # Specifies gem version of Rails to use when vendor/rails is not present
8
+ RAILS_GEM_VERSION = '2.2.2' unless defined? RAILS_GEM_VERSION
9
+
10
+ # Bootstrap the Rails environment, frameworks, and default configuration
11
+ require File.join(File.dirname(__FILE__), 'boot')
12
+
13
+ Rails::Initializer.run do |config|
14
+ # Settings in config/environments/* take precedence over those specified here.
15
+ # Application configuration should go into files in config/initializers
16
+ # -- all .rb files in that directory are automatically loaded.
17
+ # See Rails::Configuration for more options.
18
+
19
+ # Skip frameworks you're not going to use. To use Rails without a database
20
+ # you must remove the Active Record framework.
21
+ # config.frameworks -= [ :active_record, :active_resource, :action_mailer ]
22
+
23
+ # Specify gems that this application depends on.
24
+ # They can then be installed with "rake gems:install" on new installations.
25
+ # config.gem "bj"
26
+ # config.gem "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net"
27
+ # config.gem "aws-s3", :lib => "aws/s3"
28
+ config.gem 'thoughtbot-shoulda', :lib => 'shoulda/rails',
29
+ :source => 'http://gems.github.com'
30
+
31
+ # Only load the plugins named here, in the order given. By default, all plugins
32
+ # in vendor/plugins are loaded in alphabetical order.
33
+ # :all can be used as a placeholder for all plugins not explicitly named
34
+ # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
35
+
36
+ # Add additional load paths for your own custom dirs
37
+ # config.load_paths += %W( #{RAILS_ROOT}/extras )
38
+
39
+ # Force all environments to use the same logger level
40
+ # (by default production uses :info, the others :debug)
41
+ # config.log_level = :debug
42
+
43
+ # Make Time.zone default to the specified zone, and make Active Record store time values
44
+ # in the database in UTC, and return them converted to the specified local zone.
45
+ # Run "rake -D time" for a list of tasks for finding time zone names. Comment line to use default local time.
46
+ # config.time_zone = ENV['TZ'] = 'UTC'
47
+
48
+ # Your secret key for verifying cookie session data integrity.
49
+ # If you change this key, all old sessions will become invalid!
50
+ # Make sure the secret is at least 30 characters and all random,
51
+ # no regular words or you'll be exposed to dictionary attacks.
52
+ # config.action_controller.session = {
53
+ # :session_key => '_load_model_session',
54
+ # :secret => '731d6426b38a848657211af3650ea99dc064a830ec15fd20565d71ba62498382132872b2d9b549eeb5a016025c119eb821d8e66794cd380888120aa0b857386d'
55
+ # }
56
+
57
+ # Use the database for sessions instead of the cookie-based default,
58
+ # which shouldn't be used to store highly confidential information
59
+ # (create the session table with "rake db:sessions:create")
60
+ # config.action_controller.session_store = :active_record_store
61
+
62
+ # Use SQL instead of Active Record's schema dumper when creating the test database.
63
+ # This is necessary if your schema can't be completely dumped by the schema dumper,
64
+ # like if you have constraints or database-specific column types
65
+ # config.active_record.schema_format = :sql
66
+
67
+ # Activate observers that should always be running
68
+ # config.active_record.observers = :cacher, :garbage_collector
69
+ end
70
+
71
+ require 'ruby-debug'
@@ -0,0 +1,19 @@
1
+ # Settings specified here will take precedence over those in config/environment.rb
2
+
3
+ # The test environment is used exclusively to run your application's
4
+ # test suite. You never need to work with it otherwise. Remember that
5
+ # your test database is "scratch space" for the test suite and is wiped
6
+ # and recreated between test runs. Don't rely on the data there!
7
+ config.cache_classes = true
8
+
9
+ # Log error messages when you accidentally call methods on nil.
10
+ config.whiny_nils = true
11
+
12
+ # Show full error reports and disable caching
13
+ config.action_controller.consider_all_requests_local = true
14
+ config.action_controller.perform_caching = false
15
+
16
+ # Tell ActionMailer not to deliver emails to the real world.
17
+ # The :test delivery method accumulates sent emails in the
18
+ # ActionMailer::Base.deliveries array.
19
+ config.action_mailer.delivery_method = :test
@@ -0,0 +1,5 @@
1
+ ActionController::Routing::Routes.draw do |map|
2
+ map.connect ':controller/service.wsdl', :action => 'wsdl'
3
+ map.connect ':controller/:action/:id.:format'
4
+ map.connect ':controller/:action/:id'
5
+ end
@@ -0,0 +1,21 @@
1
+ ActiveRecord::Schema.define(:version => 1) do
2
+ create_table 'users', :force => true do |t|
3
+ t.column :name, :string
4
+ end
5
+
6
+ create_table 'posts', :force => true do |t|
7
+ t.column :user_id, :integer
8
+ t.column :published, :boolean, :default => true
9
+ t.column :name, :string
10
+ end
11
+
12
+ create_table 'alternates', :force => true do |t|
13
+ t.column :alternate_id, :integer
14
+ t.column :name, :string
15
+ end
16
+
17
+ create_table 'fuzzles', :force => true do |t|
18
+ t.column :fuzzle_id, :integer
19
+ t.column :name, :string
20
+ end
21
+ end
@@ -0,0 +1,82 @@
1
+ class BasicController < ActionController::Base
2
+ load_model :user
3
+ load_model :alternate, :parameter_key => :alternate_id,
4
+ :foreign_key => :alternate_id
5
+ load_model :chameleon, :class => :user
6
+ load_model :flamingo, :class => User
7
+ load_model :tucan, :class => :alternate, :parameter_key => :alternate_id,
8
+ :foreign_key => :alternate_id
9
+
10
+ def index; render :text => 'hello'; end
11
+ end
12
+ class BasicController; def rescue_action(e) raise e end; end
13
+
14
+ # Has strings for values
15
+
16
+ class StringKeyController < ActionController::Base
17
+ load_model 'user'
18
+ load_model 'alternate', :parameter_key => 'alternate_id',
19
+ :foreign_key => 'alternate_id'
20
+ load_model 'chameleon', :class => 'user'
21
+
22
+ def index; render :text => 'goodbye'; end
23
+ end
24
+ class StringKeyController; def rescue_action(e) raise e end; end
25
+
26
+ # Requires values
27
+
28
+ class RequireModelController < ActionController::Base
29
+ load_model :stuser, :class => :alternate, :parameter_key => :alternate_id,
30
+ :foreign_key => :alternate_id, :require => nil # never required
31
+ load_model :fuzzle, :parameter_key => :fuzzle_id, :foreign_key => :fuzzle_id,
32
+ :require => [:newer] # required for newer action
33
+ load_model :user, :require => true # required for all actions
34
+
35
+ def index; render :text => 'whatever'; end
36
+ def new; render :text => 'whatever 2'; end
37
+ def newer; render :text => 'whatever 3'; end
38
+ end
39
+ class RequireModelController; def rescue_action(e) raise e end; end
40
+
41
+ # Restriction options
42
+
43
+ class RestrictOptionsController < ActionController::Base
44
+ load_model :user, :only => [:index]
45
+ load_model :alternate, :except => [:index], :parameter_key => :alternate_id,
46
+ :foreign_key => :alternate_id
47
+
48
+ def index; render :text => 'ran index'; end
49
+ def show; render :text => 'ran show'; end
50
+ end
51
+ class RequireModelController; def rescue_action(e) raise e end; end
52
+
53
+ class KeysController < ActionController::Base
54
+ # Expects to use fuzzle_id as parameter key against User class with FK of :id
55
+ load_model :user, :parameter_key => :fuzzle_id
56
+
57
+ # Expects to use :fuzzle_id as FK and parameter key against Fuzzle class
58
+ # (normal operation)
59
+ load_model :fuzzler, :parameter_key => :fuzzle_id, :foreign_key => :fuzzle_id,
60
+ :class => :fuzzle
61
+
62
+ def index; render :text => 'hello'; end
63
+ end
64
+ class KeysController; def rescue_action(e) raise e end; end
65
+
66
+ # Load model through existing model
67
+ class ThroughController < ActionController::Base
68
+ load_model :user, :parameter_key => :user_id
69
+ load_model :post, :through => :user, :except => [:show]
70
+ # proving that except and only work
71
+ load_model :post, :through => :user, :parameter_key => 'weird_id',
72
+ :require => true, :only => [:show]
73
+
74
+ load_model :post, :through => :user, :association => :unpublished_posts,
75
+ :require => true, :only => [:show_unpublished]
76
+
77
+ def index; render :text => 'index'; end
78
+ def show; render :text => 'show'; end
79
+ def show_unpublished; render :text => 'unpublished'; end
80
+
81
+ end
82
+ class ThroughController; def rescue_action(e) raise e end; end
@@ -0,0 +1,26 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class KeysControllerTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ super
7
+ @request = ActionController::TestRequest.new
8
+ @response = ActionController::TestResponse.new
9
+ @controller = KeysController.new
10
+ @user = User.create!(:name => 'Foo')
11
+ @fuzzler = Fuzzle.create!(:name => 'Bar', :fuzzle_id => 300)
12
+ end
13
+
14
+ def test_should_find_user_using_fuzzle_id_as_param_key
15
+ get :index, :fuzzle_id => @user.id
16
+ assert_equal @user.id, assigns(:user).id
17
+ assert_nil assigns(:fuzzler)
18
+ end
19
+
20
+ def test_should_find_fuzzler_using_fuzzle_id_as_param_and_foreign_key
21
+ get :index, :fuzzle_id => @fuzzler.fuzzle_id
22
+ assert_equal @fuzzler.id, assigns(:fuzzler).id
23
+ assert_nil assigns(:user)
24
+ end
25
+
26
+ end
@@ -0,0 +1,85 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class LoadModelTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ super
7
+ @request = ActionController::TestRequest.new
8
+ @response = ActionController::TestResponse.new
9
+ @controller = BasicController.new
10
+ @foo = User.create!(:name => 'Foo')
11
+ end
12
+
13
+ def teardown
14
+ Alternate.delete_all
15
+ User.delete_all
16
+ end
17
+
18
+ context "when parameter" do
19
+ context "is provided" do
20
+ setup { get :index, :id => @foo.id }
21
+ should("find record") { assert_equal @foo.id, assigns(:user).id }
22
+ end # is provided
23
+
24
+ context "is not provided" do
25
+ setup { get :index }
26
+ should("not assign any record") { assert_nil assigns(:user) }
27
+ end # is not provided
28
+
29
+ context "does not match existing record" do
30
+ setup { get :index, :id => (@foo.id + 1) }
31
+ should("not assign any record") { assert_nil assigns(:user) }
32
+ end # does not match existing record
33
+ end # when parameter
34
+
35
+ def test_should_find_record_with_alternate_id_as_expected_param_key
36
+ alt = Alternate.create!(:name => 'Alternate', :alternate_id => 100)
37
+ get :index, :alternate_id => alt.alternate_id
38
+ assert_equal alt.id, assigns(:alternate).id
39
+ assert_equal alt.alternate_id, assigns(:alternate).alternate_id
40
+ end
41
+
42
+ def test_should_find_nothing_when_alternate_id_does_not_match_record
43
+ alt = Alternate.create!(:name => 'Alternate', :alternate_id => 99)
44
+ get :index, :alternate_id => 100
45
+ assert_nil assigns(:alternate)
46
+ end
47
+
48
+ def test_should_find_chameleon_in_user_table
49
+ get :index, :id => @foo.id
50
+ assert_equal @foo.id, assigns(:chameleon).id
51
+ end
52
+
53
+ def test_should_not_find_chameleon_in_user_table_with_nonexistent_id
54
+ get :index, :id => (@foo.id + 1)
55
+ assert_nil assigns(:chameleon)
56
+ end
57
+
58
+ def test_should_find_flamingo_in_user_table_even_when_class_name_is_constant
59
+ get :index, :id => @foo.id
60
+ assert_equal @foo.id, assigns(:flamingo).id
61
+ end
62
+
63
+ def test_should_not_find_flamingo_in_user_table_when_class_name_is_constant
64
+ get :index, :id => (@foo.id + 1)
65
+ assert_nil assigns(:flamingo)
66
+ end
67
+
68
+ def test_should_find_tucan_in_users_with_alternate_class_and_key
69
+ alt = Alternate.create!(:name => 'Alternate', :alternate_id => 100)
70
+ get :index, :alternate_id => alt.alternate_id
71
+ assert_equal alt.id, assigns(:tucan).id
72
+ end
73
+
74
+ def test_should_not_find_tucan_in_users_with_alternate_class_and_key
75
+ alt = Alternate.create!(:name => 'Alternate', :alternate_id => 100)
76
+ get :index, :alternate_id => (alt.alternate_id + 1)
77
+ assert_nil assigns(:tucan)
78
+ end
79
+
80
+ def test_should_not_find_record_if_key_value_is_not_an_integer
81
+ get :index, :id => 'abc'
82
+ assert_nil assigns(:user)
83
+ end
84
+
85
+ end
@@ -0,0 +1,45 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ require File.dirname(__FILE__) + '/controller_helper'
3
+
4
+ class RequireModelControllerTest < Test::Unit::TestCase
5
+
6
+ def setup
7
+ super
8
+ @request = ActionController::TestRequest.new
9
+ @response = ActionController::TestResponse.new
10
+ @controller = RequireModelController.new
11
+ @foo = User.create!(:name => 'Foo')
12
+ end
13
+
14
+ def test_should_find_record_if_required_to_find_record_and_record_is_found
15
+ get :index, :id => @foo.id
16
+ assert_equal @foo.id, assigns(:user).id
17
+ end
18
+
19
+ def test_should_not_require_value_if_required_is_nil
20
+ get :new, :id => @foo.id
21
+ assert_equal @foo.id, assigns(:user).id
22
+ end
23
+
24
+ def test_should_not_require_value_if_required_is_for_different_action
25
+ fuzz = Fuzzle.create!(:name => 'Fuzzy', :fuzzle_id => 200)
26
+ get :new, :id => @foo.id, :fuzzle_id => fuzz.id
27
+ assert_equal @foo.id, assigns(:user).id
28
+ assert_nil assigns(:stuser)
29
+ assert_nil assigns(:fuzzle)
30
+ end
31
+
32
+ def test_should_raise_error_if_required_is_scoped_and_record_not_found
33
+ fuzz = Fuzzle.create!(:name => 'Fuzzy', :fuzzle_id => 200)
34
+ assert_raise(ThumbleMonks::LoadModel::RequiredRecordNotFound) do
35
+ get :newer, :id => @foo.id, :fuzzle_id => (fuzz.id + 1)
36
+ end
37
+ end
38
+
39
+ def test_should_raise_error_if_required_is_true_and_record_not_found
40
+ assert_raise(ThumbleMonks::LoadModel::RequiredRecordNotFound) do
41
+ get :new, :id => (@foo.id + 1)
42
+ end
43
+ end
44
+
45
+ end
@@ -0,0 +1,34 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class RestrictOptionsControllerTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ super
7
+ @request = ActionController::TestRequest.new
8
+ @response = ActionController::TestResponse.new
9
+ @controller = RestrictOptionsController.new
10
+ @foo = User.create!(:name => 'Foo')
11
+ @alt = Alternate.create!(:name => 'Bar', :alternate_id => 100)
12
+ end
13
+
14
+ def test_should_load_user_for_index
15
+ get :index, :id => @foo.id, :alternate_id => @alt.id
16
+ assert_equal @foo.id, assigns(:user).id
17
+ end
18
+
19
+ def test_should_not_load_alternate_for_index
20
+ get :index, :id => @foo.id, :alternate_id => @alt.alternate_id
21
+ assert_nil assigns(:alternate)
22
+ end
23
+
24
+ def test_should_load_alternate_for_show
25
+ get :show, :id => @foo.id, :alternate_id => @alt.alternate_id
26
+ assert_equal @alt, assigns(:alternate)
27
+ end
28
+
29
+ def test_should_not_load_user_for_show
30
+ get :show, :id => @foo.id, :alternate_id => @alt.alternate_id
31
+ assert_nil assigns(:user)
32
+ end
33
+
34
+ end
@@ -0,0 +1,52 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ require File.dirname(__FILE__) + '/controller_helper'
3
+
4
+ class StringKeyLoadModelTest < Test::Unit::TestCase
5
+
6
+ def setup
7
+ super
8
+ @request = ActionController::TestRequest.new
9
+ @response = ActionController::TestResponse.new
10
+ @controller = StringKeyController.new
11
+ @foo = User.create!(:name => 'Foo')
12
+ end
13
+
14
+ def test_should_find_record_and_assign_to_instance_variable_if_param_provided
15
+ get :index, :id => @foo.id
16
+ assert_equal @foo.id, assigns(:user).id
17
+ end
18
+
19
+ def test_should_return_nil_if_expected_param_not_provided
20
+ get :index
21
+ assert_nil assigns(:user)
22
+ end
23
+
24
+ def test_should_return_nil_if_expected_param_does_not_match_record
25
+ get :index, :id => (@foo.id + 1) # Should not belong to an existing user
26
+ assert_nil assigns(:user)
27
+ end
28
+
29
+ def test_should_find_record_with_alternate_id_as_expected_param_key
30
+ alt = Alternate.create!(:name => 'Alternate', :alternate_id => 100)
31
+ get :index, :alternate_id => alt.alternate_id
32
+ assert_equal alt.id, assigns(:alternate).id
33
+ assert_equal alt.alternate_id, assigns(:alternate).alternate_id
34
+ end
35
+
36
+ def test_should_find_nothing_when_alternate_id_does_not_match_record
37
+ alt = Alternate.create!(:name => 'Alternate', :alternate_id => 99)
38
+ get :index, :alternate_id => 100
39
+ assert_nil assigns(:alternate)
40
+ end
41
+
42
+ def test_should_find_chameleon_in_user_table
43
+ get :index, :id => @foo.id
44
+ assert_equal @foo.id, assigns(:chameleon).id
45
+ end
46
+
47
+ def test_should_not_find_chameleon_in_user_table_with_nonexistent_id
48
+ get :index, :id => (@foo.id + 1)
49
+ assert_nil assigns(:chameleon)
50
+ end
51
+
52
+ end
@@ -0,0 +1,61 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ require File.dirname(__FILE__) + '/controller_helper'
3
+
4
+ class ThroughControllerTest < Test::Unit::TestCase
5
+ def setup
6
+ super
7
+ @request = ActionController::TestRequest.new
8
+ @response = ActionController::TestResponse.new
9
+ @controller = ThroughController.new
10
+ @user = User.create!(:name => 'Foo')
11
+ @post = @user.posts.create!(:name => 'Foo post')
12
+ end
13
+
14
+ context "index with valid ids" do
15
+ setup do
16
+ get :index, :user_id => @user.id, :id => @post.id
17
+ end
18
+
19
+ should_assign_to :user, :equals => "@user"
20
+ should_assign_to :post, :equals => "@post"
21
+ end # with valid ids
22
+
23
+ context "show_unpublished with valid id" do
24
+ setup do
25
+ @unpublished_post = @user.posts.create!{ |p| p.published = false }
26
+ get :show_unpublished, :user_id => @user.id, :id => @unpublished_post.id
27
+ end
28
+
29
+ should_assign_to :user, :equals => "@user"
30
+ should_assign_to :post, :equals => "@post"
31
+ end
32
+
33
+ context "index with invalid post id" do
34
+ setup do
35
+ get :index, :user_id => @user.id, :id => -1
36
+ end
37
+
38
+ should_assign_to :user, :equals => "@user"
39
+ should_not_assign_to :post
40
+ end # with invalid post id
41
+
42
+ context "show with alternative post via weird_id" do
43
+ context "has exisiting records" do
44
+ setup do
45
+ get :show, :user_id => @user.id, :weird_id => @post.id
46
+ end
47
+
48
+ should_assign_to :user, :equals => "@user"
49
+ should_assign_to :post, :equals => "@post"
50
+ end # has existing records
51
+
52
+ context "has nonexistent records for required action" do
53
+ should "flail with exception" do
54
+ assert_raise(ThumbleMonks::LoadModel::RequiredRecordNotFound) do
55
+ get :show, :user_id => @user.id, :weird_id => -1
56
+ end
57
+ end
58
+ end # has nonexistant records for required action
59
+ end # show with alternative post via weird_id
60
+
61
+ end
@@ -0,0 +1,27 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+ ENV["RAILS_ROOT"] = File.expand_path(File.join(File.dirname(__FILE__), '..', 'rails'))
3
+ require File.expand_path(File.join(ENV["RAILS_ROOT"], 'config', 'environment'))
4
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'load_model'))
5
+ require 'test_help'
6
+ load(File.dirname(__FILE__) + "/../rails/db/schema.rb")
7
+
8
+ class User < ActiveRecord::Base
9
+ has_many :posts, :conditions => {:published => true}
10
+ has_many :unpublished_posts, :conditions => {:published => false}, :class_name => 'Post'
11
+ end
12
+ class Post < ActiveRecord::Base
13
+ belongs_to :user
14
+ end
15
+ class Alternate < ActiveRecord::Base; end
16
+ class Fuzzle < ActiveRecord::Base; end
17
+
18
+ class Test::Unit::TestCase
19
+ def teardown
20
+ Fuzzle.delete_all
21
+ Alternate.delete_all
22
+ Post.delete_all
23
+ User.delete_all
24
+ end
25
+ end
26
+
27
+ require File.dirname(__FILE__) + '/functional/controller_helper'
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: thumblemonks-load_model
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Justin Knowlden
8
+ - Gabriel Gironda
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2009-01-03 00:00:00 -08:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description: Rails Controller plugin that provides easy and useful macros for tying models and requests together
18
+ email:
19
+ - gus@gusg.us
20
+ - gabriel.gironda@gmail.com
21
+ executables: []
22
+
23
+ extensions: []
24
+
25
+ extra_rdoc_files:
26
+ - HISTORY.markdown
27
+ - README.markdown
28
+ files:
29
+ - HISTORY.markdown
30
+ - MIT-LICENSE
31
+ - README.markdown
32
+ - Rakefile
33
+ - lib/load_model.rb
34
+ - load_model.gemspec
35
+ has_rdoc: true
36
+ homepage: http://github.com/thumblemonks/load_model
37
+ post_install_message: Choosy prima donnas choose Thumble Monks
38
+ rdoc_options:
39
+ - --line-numbers
40
+ - --inline-source
41
+ - --title
42
+ - Load Model
43
+ - --main
44
+ - README.markdown
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "1.2"
58
+ version:
59
+ requirements: []
60
+
61
+ rubyforge_project: load_model
62
+ rubygems_version: 1.2.0
63
+ signing_key:
64
+ specification_version: 2
65
+ summary: Rails Controller plugin that provides easy and useful macros for tying models and requests together
66
+ test_files:
67
+ - rails/app/controllers/application.rb
68
+ - rails/config/boot.rb
69
+ - rails/config/database.yml
70
+ - rails/config/environment.rb
71
+ - rails/config/environments/test.rb
72
+ - rails/config/routes.rb
73
+ - rails/db/schema.rb
74
+ - rails/db/test.db
75
+ - rails/log/test.log
76
+ - test/functional/controller_helper.rb
77
+ - test/functional/keys_controller_test.rb
78
+ - test/functional/load_model_test.rb
79
+ - test/functional/require_model_controller_test.rb
80
+ - test/functional/restrict_options_controller_test.rb
81
+ - test/functional/string_key_load_model_test.rb
82
+ - test/functional/through_controller_test.rb
83
+ - test/test_helper.rb