acts_as_multipart_form 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. data/CHANGELOG +3 -0
  2. data/Gemfile +27 -0
  3. data/Gemfile.lock +157 -0
  4. data/LICENSE.txt +20 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.rdoc +19 -0
  7. data/Rakefile +65 -0
  8. data/VERSION +1 -0
  9. data/acts_as_multipart_form.gemspec +163 -0
  10. data/app/controllers/multipart_form/in_progress_forms_controller.rb +0 -0
  11. data/app/models/multipart_form/in_progress_form.rb +20 -0
  12. data/app/views/multipart_form/_breadcrumb.html.erb +21 -0
  13. data/app/views/multipart_form/_index_links.html.erb +20 -0
  14. data/app/views/multipart_form/in_progress_form/index.html.erb +0 -0
  15. data/app/views/multipart_form/in_progress_form/index.html.haml +0 -0
  16. data/lib/acts_as_multipart_form.rb +2 -0
  17. data/lib/acts_as_multipart_form/config.rb +36 -0
  18. data/lib/acts_as_multipart_form/engine.rb +4 -0
  19. data/lib/acts_as_multipart_form/multipart_form_in_controller.rb +301 -0
  20. data/lib/acts_as_multipart_form/multipart_form_in_model.rb +105 -0
  21. data/lib/acts_as_multipart_form/railtie.rb +14 -0
  22. data/lib/generators/acts_as_multipart_form/install_generator.rb +44 -0
  23. data/lib/generators/acts_as_multipart_form/templates/config.rb +6 -0
  24. data/lib/generators/acts_as_multipart_form/templates/migrations/install_migration.rb.erb +17 -0
  25. data/spec/acts_as_multipart_form_spec.rb +7 -0
  26. data/spec/dummy/Rakefile +7 -0
  27. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  28. data/spec/dummy/app/controllers/people_controller.rb +53 -0
  29. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  30. data/spec/dummy/app/models/person.rb +5 -0
  31. data/spec/dummy/app/models/person_with_multiple_actsas.rb +5 -0
  32. data/spec/dummy/app/models/person_with_multiple_forms.rb +4 -0
  33. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  34. data/spec/dummy/app/views/people/_job_info.html.erb +8 -0
  35. data/spec/dummy/app/views/people/_person_info.html.erb +8 -0
  36. data/spec/dummy/app/views/people/hire_form.html.erb +10 -0
  37. data/spec/dummy/app/views/people/index.html.erb +16 -0
  38. data/spec/dummy/app/views/people/show.html.erb +0 -0
  39. data/spec/dummy/config.ru +4 -0
  40. data/spec/dummy/config/application.rb +45 -0
  41. data/spec/dummy/config/boot.rb +10 -0
  42. data/spec/dummy/config/database.yml +22 -0
  43. data/spec/dummy/config/environment.rb +5 -0
  44. data/spec/dummy/config/environments/development.rb +26 -0
  45. data/spec/dummy/config/environments/production.rb +49 -0
  46. data/spec/dummy/config/environments/test.rb +35 -0
  47. data/spec/dummy/config/initializers/acts_as_multipart_form.rb +6 -0
  48. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  49. data/spec/dummy/config/initializers/inflections.rb +10 -0
  50. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  51. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  52. data/spec/dummy/config/initializers/session_store.rb +8 -0
  53. data/spec/dummy/config/locales/en.yml +5 -0
  54. data/spec/dummy/config/routes.rb +66 -0
  55. data/spec/dummy/db/migrate/20110715180834_create_people.rb +13 -0
  56. data/spec/dummy/db/migrate/20110722130249_create_multipart_form_tables.rb +17 -0
  57. data/spec/dummy/db/schema.rb +31 -0
  58. data/spec/dummy/features/form_breadcrumb.feature +75 -0
  59. data/spec/dummy/features/form_submission.feature +23 -0
  60. data/spec/dummy/features/index_links.feature +56 -0
  61. data/spec/dummy/features/step_definitions/acts_as_multipart_form_steps.rb +30 -0
  62. data/spec/dummy/features/step_definitions/config_steps.rb +23 -0
  63. data/spec/dummy/features/step_definitions/web_steps.rb +214 -0
  64. data/spec/dummy/features/support/env.rb +15 -0
  65. data/spec/dummy/features/support/paths.rb +31 -0
  66. data/spec/dummy/features/support/selectors.rb +39 -0
  67. data/spec/dummy/public/404.html +26 -0
  68. data/spec/dummy/public/422.html +26 -0
  69. data/spec/dummy/public/500.html +26 -0
  70. data/spec/dummy/public/favicon.ico +0 -0
  71. data/spec/dummy/public/javascripts/application.js +2 -0
  72. data/spec/dummy/public/javascripts/controls.js +965 -0
  73. data/spec/dummy/public/javascripts/dragdrop.js +974 -0
  74. data/spec/dummy/public/javascripts/effects.js +1123 -0
  75. data/spec/dummy/public/javascripts/prototype.js +6001 -0
  76. data/spec/dummy/public/javascripts/rails.js +191 -0
  77. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  78. data/spec/dummy/script/rails +6 -0
  79. data/spec/in_progress_form_spec.rb +43 -0
  80. data/spec/integration/navigation_spec.rb +9 -0
  81. data/spec/multipart_form_in_controller_integeration_spec.rb +23 -0
  82. data/spec/multipart_form_in_controller_spec.rb +360 -0
  83. data/spec/multipart_form_in_model_integration_spec.rb +30 -0
  84. data/spec/multipart_form_in_model_spec.rb +156 -0
  85. data/spec/spec_helper.rb +38 -0
  86. metadata +296 -0
@@ -0,0 +1,20 @@
1
+ module MultipartForm
2
+ # Stores information about multipart forms in progress
3
+ # Useful when displaying information about the form especially when a user
4
+ # stops halfway through a form and comes back to it
5
+ #
6
+ # form_subject is a polymorphic relationship to the model that uses the form
7
+ #
8
+ # form_name relates to the name of the form on the model on the line
9
+ # acts_as_multipart_form :form_name => {:type => ...
10
+ # @author Jeremiah Hemphill
11
+ class InProgressForm < ::ActiveRecord::Base
12
+ set_table_name "multipart_form_in_progress_forms"
13
+ belongs_to :form_subject, :polymorphic => true
14
+
15
+ validates_presence_of :form_subject
16
+ validates_presence_of :form_name
17
+ validates_presence_of :last_completed_step
18
+ validates_inclusion_of :completed, :in => [true, false]
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ <div class='multipart_form_breadcrumb'>
2
+ <% if ActsAsMultipartForm.config.show_previous_next_links %>
3
+ <div class='multipart_form_breadcrumb_previous'>
4
+ <%= link_to "Previous", send(@multipart_form_path, :id => @form_subject.id, :multipart_form_part => @previous_multipart_form_part ) %>
5
+ </div>
6
+ <% end %>
7
+ <div class='multipart_form_breadcrumb_parts'>
8
+ <% @available_multipart_form_parts.each do |part| %>
9
+ <% if part[:name].to_s != @multipart_form_part.to_s %>
10
+ <%= link_to part[:name].to_s.titleize, send(@multipart_form_path, :id => @form_subject.id, :multipart_form_part => part[:name]) %>
11
+ <% else %>
12
+ <%= part[:name].to_s.titleize %>
13
+ <% end %>
14
+ <% end %>
15
+ </div>
16
+ <% if ActsAsMultipartForm.config.show_previous_next_links %>
17
+ <div class='multipart_form_breadcrumb_next'>
18
+ <%= link_to "Next", send(@multipart_form_path, :id => @form_subject.id, :multipart_form_part => @next_multipart_form_part ) %>
19
+ </div>
20
+ <% end %>
21
+ </div>
@@ -0,0 +1,20 @@
1
+ <div class='multipart_form_index_links'>
2
+ <div class='multipart_form_index_links_links'>
3
+ <% @multipart_form_index_parts[locals[:form_subject].id][:parts].each do |part| %>
4
+ <% if ActsAsMultipartForm.config.use_numbered_parts_on_index %>
5
+ <%= link_to part[:number].to_s, send(@multipart_form_path, :id => locals[:form_subject].id, :multipart_form_part => part[:name]) %>
6
+ <% else %>
7
+ <%= link_to part[:name].to_s.titleize, send(@multipart_form_path, :id => locals[:form_subject].id, :multipart_form_part => part[:name]) %>
8
+ <% end %>
9
+ <% end %>
10
+ </div>
11
+ <% if ActsAsMultipartForm.config.show_completed %>
12
+ <div class='multipart_form_index_links_complete'>
13
+ <% if @multipart_form_index_parts[locals[:form_subject].id][:completed] %>
14
+ Complete
15
+ <% else %>
16
+ Incomplete
17
+ <% end %>
18
+ </div>
19
+ <% end %>
20
+ </div>
@@ -0,0 +1,2 @@
1
+ require "acts_as_multipart_form/railtie"
2
+ require "acts_as_multipart_form/engine"
@@ -0,0 +1,36 @@
1
+ # this file was stolen from kaminari
2
+ require 'active_support/configurable'
3
+
4
+ module ActsAsMultipartForm
5
+
6
+ # create new configs by passing a block with the config assignment
7
+ def self.configure(&block)
8
+ yield @config ||= ActsAsMultipartForm::Configuration.new
9
+ end
10
+
11
+ def self.config
12
+ @config
13
+ end
14
+
15
+ # setup config data
16
+ class Configuration
17
+ include ActiveSupport::Configurable
18
+ config_accessor :show_completed
19
+ config_accessor :show_incomplete_parts
20
+ config_accessor :use_numbered_parts_on_index
21
+ config_accessor :show_previous_next_links
22
+
23
+ def param_name
24
+ config.param_name.respond_to?(:call) ? config.param_name.call() : config.param_name
25
+ end
26
+ end
27
+
28
+ # setup default options
29
+ # this should match the generator config that goes in the initializer file
30
+ configure do |config|
31
+ config.show_completed = true
32
+ config.show_incomplete_parts = false
33
+ config.use_numbered_parts_on_index = true
34
+ config.show_previous_next_links = true
35
+ end
36
+ end
@@ -0,0 +1,4 @@
1
+ module ActsAsMultipartForm
2
+ class Engine < ::Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,301 @@
1
+ module ActsAsMultipartForm
2
+
3
+ # Specify this to let the controller know how to setup the multipart forms.
4
+ # This sets up the form action, the form parts, and any other needed options.
5
+ # Each controller can have multiple multipart forms included on it
6
+ #
7
+ # The controller expects there to be an action for every form part for form_part_name and form_part_name_update
8
+ # There are currently no checks to verify these actions but an exception will be thrown when a missing
9
+ # action is called
10
+ module MultipartFormInController
11
+
12
+ def self.included(base)
13
+ base.extend ClassMethods
14
+ end
15
+
16
+ module ClassMethods
17
+ # Sets up the multipart form handler with the data needed to create and move through a multipart form
18
+ # The arguments takes several important values including:
19
+ # name: The name of the multipart form. This creates a controller action with that name that can be used in routes and other situations
20
+ # parts: An array of multipart form parts. Each part must have a corresponding part_name and part_name_update method
21
+ # model: The name of the model used to identify the multipart form. Defaults to the singularized name of the controller.
22
+ # form_route: The route for the form as specified in the config/routes file. Defaults to model_form_name downcased.
23
+ # show_route: The route the form redirects to once the last part is filled out. Defaults to the name of the model, downcased.
24
+ #
25
+ # The args parameter is an array of hashes and multiple multipart forms can be specified with a single acts_as_multipart_form call.
26
+ # To keep the lines from being too long, acts_as_multipart_form can be called multiple times to setup the forms
27
+ #
28
+ # sample set of multipart form actions
29
+ # def person_info
30
+ # @person = Person.find(params[:id])
31
+ # end
32
+ #
33
+ # def person_info_update
34
+ # @person = Person.find(params[:id])
35
+ # @person = Person.new if @person.nil?
36
+ #
37
+ # valid = @person.update_attributes(params[:person])
38
+ # return {:valid => valid, :errors => @person.errors}
39
+ # end
40
+ #
41
+ # def job_info
42
+ # @job_position = JobPosition.new
43
+ # @job_position.person = Person.find(load_multipart_form_data(form_instance_id, :person))
44
+ # end
45
+ #
46
+ # def job_info_update
47
+ # valid = @job_position.update_attributes(params[:job_position])
48
+ # return {:valid => valid, :errors => @job_position.errors}
49
+ # end
50
+ #
51
+ # @param [Array] args An array of hashes that determines the data for a multipart form
52
+ def acts_as_multipart_form(*args)
53
+
54
+ mattr_accessor :multipart_forms unless self.respond_to?(:multipart_forms)
55
+ self.multipart_forms = {} unless self.multipart_forms.is_a?(Hash)
56
+
57
+ forms = []
58
+ args.each do |arg|
59
+ # add the update parts
60
+ parts = arg[:parts]
61
+ arg[:parts] = []
62
+ parts.each do |part|
63
+ arg[:parts] << part
64
+ arg[:parts] << (part.to_s + "_update").to_sym
65
+ end
66
+ # sets default model if it is not set
67
+ arg[:model] = self.to_s.gsub("Controller", "").singularize unless arg.has_key?(:model)
68
+ arg[:form_route] = (arg[:model].downcase + "_" + arg[:name].to_s) unless arg.has_key?(:form_route)
69
+ arg[:show_route] = (arg[:model].downcase) unless arg.has_key?(:show_route)
70
+ # copy args to fields
71
+ self.multipart_forms[arg[:name]] = arg
72
+ forms << arg[:name]
73
+ end
74
+
75
+ before_filter :multipart_form_handler, :only => forms
76
+
77
+ include ActsAsMultipartForm::MultipartFormInController::InstanceMethods
78
+
79
+ end
80
+ end
81
+
82
+ module InstanceMethods
83
+
84
+ # A bad hack to load the multipart form information for the index page
85
+ # This must be called if you want to use the multipart_form/index_links partial
86
+ #
87
+ # Adds several instance variables available for the view
88
+ #
89
+ # @param [Symbol] form_name The name of the form
90
+ # @param [Array] form_subjects An array of active record objects that are form subjects for the given form
91
+ def load_multipart_form_index_links(form_name, form_subjects)
92
+ @multipart_form_index_parts = {}
93
+ form_subjects.each do |form_subject|
94
+ in_progress_form = find_or_create_multipart_in_progress_form(form_name, form_subject)
95
+ @multipart_form_index_parts[form_subject.id] = {}
96
+ @multipart_form_index_parts[form_subject.id][:parts] = get_available_multipart_form_parts(form_name, in_progress_form.last_completed_step)
97
+ @multipart_form_index_parts[form_subject.id][:completed] = in_progress_form.completed
98
+ end
99
+ @multipart_form_path = (self.multipart_forms[form_name][:form_route] + "_path").to_sym
100
+ end
101
+
102
+ # Handles multipart form setup on the controller
103
+ # Automatically called on the hire form action as a before filter
104
+ #
105
+ # It adds a bunch of instance variables to the controller so they are accessible to the view page.
106
+ # Not sure if this is the best way to do things
107
+ def multipart_form_handler
108
+ form_name = params[:action].to_sym
109
+ form_subject_id = params[:id]
110
+
111
+ form_subject = find_or_create_multipart_form_subject(form_name, form_subject_id)
112
+ params[:id] = form_subject.id
113
+
114
+ in_progress_form = find_or_create_multipart_in_progress_form(form_name, form_subject)
115
+
116
+ # set the part based on the params or in progress form
117
+ if params[:multipart_form_part]
118
+ part = params[:multipart_form_part].to_sym
119
+ elsif in_progress_form.last_completed_step != "none"
120
+ part = get_next_multipart_form_part(form_name, in_progress_form.last_completed_step.to_sym)
121
+ else
122
+ part = self.multipart_forms[form_name][:parts].first
123
+ end
124
+
125
+ # call and save the part information
126
+ if(part && self.multipart_forms[form_name][:parts].include?(part.to_sym))
127
+ result = self.send(part)
128
+
129
+ if(part.match(/_update$/))
130
+ if(result && result[:valid])
131
+ completed = redirect_to_next_multipart_form_part(form_name, form_subject, part)
132
+ in_progress_form.update_attributes(:last_completed_step => part, :completed => completed)
133
+ else
134
+ # render the previous page but stay on this page so we keep the errors
135
+ part = get_previous_multipart_form_part(form_name, part)
136
+ end
137
+ end
138
+ # get two previous parts so the previous link works
139
+ previous_part = get_previous_multipart_form_part(form_name, part)
140
+ @previous_multipart_form_part = get_previous_multipart_form_part(form_name, previous_part).to_s
141
+ # needs to be a string so that the view can read it
142
+ @multipart_form_part = part.to_s
143
+ @next_multipart_form_part = get_next_multipart_form_part(form_name, part).to_s
144
+ @form_subject = form_subject
145
+ @available_multipart_form_parts = get_available_multipart_form_parts(form_name, in_progress_form.last_completed_step)
146
+ @multipart_form_path = (self.multipart_forms[form_name][:form_route] + "_path").to_sym
147
+ @multipart_form_complete = in_progress_form.completed
148
+ end
149
+ end
150
+
151
+ # Determines if the symbol matches a multipart form name
152
+ #
153
+ # @param [Symbol] sym A name that may or may not correspond to a multipart form name
154
+ # @return [Boolean] Returns true if the symbol matches a multipart form name
155
+ def multipart_form_action?(sym)
156
+ self.multipart_forms.keys.include?(sym)
157
+ end
158
+
159
+ # Gets the next multipart form part for the form or returns the current part if it is first
160
+ #
161
+ # @param [Symbol] form The name of the multipart form
162
+ # @param [Symbol] part The name of the current part
163
+ # @returns [Symbol] The name of the next part
164
+ def get_previous_multipart_form_part(form, part)
165
+ part_index = self.multipart_forms[form][:parts].index(part)
166
+ if part_index > 0
167
+ return self.multipart_forms[form][:parts][part_index - 1]
168
+ else
169
+ return part
170
+ end
171
+ end
172
+
173
+ # Gets the previous multipart form part for the form or returns the current part if it is first
174
+ #
175
+ # @param [Symbol] form The name of the multipart form
176
+ # @param [Symbol] part The name of the current part
177
+ # @returns [Symbol] The name of the previous part
178
+ def get_next_multipart_form_part(form, part)
179
+ part_index = self.multipart_forms[form][:parts].index(part)
180
+ if part_index < self.multipart_forms[form][:parts].length - 1
181
+ return self.multipart_forms[form][:parts][part_index + 1]
182
+ else
183
+ return part
184
+ end
185
+ end
186
+
187
+ # Determines if the given multipart form part is the last part of the form
188
+ #
189
+ # @param [Symbol] form The name of the multipart form
190
+ # @param [Symbol] part The name o the current part
191
+ # @returns [Boolean] True if the given part matches the last part
192
+ def last_multipart_form_part?(form, part)
193
+ self.multipart_forms[form][:parts].last == part
194
+ end
195
+
196
+ # Determines if the given multipart form part is the first part of the form
197
+ #
198
+ # @param [Symbol] form The name of the multipart form
199
+ # @param [Symbol] part The name o the current part
200
+ # @returns [Boolean] True if the given part matches the first part
201
+ def first_multipart_form_part?(form, part)
202
+ self.multipart_forms[form][:parts].first == part
203
+ end
204
+
205
+
206
+ # Given a form name and a form subject id, it creates the form subject
207
+ # The form subject is defined by the id and the multipart form's model attribute
208
+ # The subject is created with values and saved without validations (this might change in the future)
209
+ #
210
+ # @param [Symbol] form_name The name of the multipart form
211
+ # @param [Integer] form_dubject_id The id of the form subject (could be nil)
212
+ # @return [FormSubject] The form subject object based on the multipart form's model or nil if the id is set and not found
213
+ def find_or_create_multipart_form_subject(form_name, form_subject_id)
214
+ # find or create the form subject
215
+ model = self.multipart_forms[form_name][:model]
216
+ if form_subject_id
217
+ form_subject = model.constantize.find(form_subject_id)
218
+ else
219
+ form_subject = model.constantize.new()
220
+ form_subject.save(:validate => false)
221
+ end
222
+ return form_subject
223
+ end
224
+
225
+ # Returns the InProgressForm object when given the form name and subject
226
+ # Creates the InPorgressForm object if it doesn't exist for the given form name/form subject pair
227
+ #
228
+ # @param [Symbol] form_name The name of the multipart form
229
+ # @param [FormSubject] form_subject The multipart form's subject
230
+ # @returns [InProgressForm] The associated or new in progress form object
231
+ def find_or_create_multipart_in_progress_form(form_name, form_subject)
232
+ # find or create the in progress form
233
+ # not sure why the polymorphic relationship isn't working here
234
+ in_progress_form = MultipartForm::InProgressForm.where(
235
+ :form_subject_id => form_subject.id,
236
+ :form_subject_type => form_subject.class.to_s,
237
+ :form_name => form_name).first
238
+ if !in_progress_form
239
+ in_progress_form = MultipartForm::InProgressForm.create(
240
+ :form_subject_id => form_subject.id,
241
+ :form_subject_type => form_subject.class.to_s,
242
+ :form_name => form_name,
243
+ :last_completed_step => "none",
244
+ :completed => false)
245
+ end
246
+ return in_progress_form
247
+ end
248
+
249
+ # Adds a redirect based on the information passed in.
250
+ # If on the last part of the form, tries to redirect to the view page,
251
+ # otherwise to the next form part.
252
+ #
253
+ # This method needs signficantly more testing (7-20-2011)
254
+ #
255
+ # @param [Sybmol] form_name The name of the form
256
+ # @param [FormSubject] form_subject The subject of the form
257
+ # @param [Symbol] part The current form part
258
+ def redirect_to_next_multipart_form_part(form_name, form_subject, part)
259
+ # set highest completed part to the current part4
260
+ if(last_multipart_form_part?(form_name, part))
261
+ # render the view page(not sure how to do this)
262
+ redirect_to( send(self.multipart_forms[form_name][:show_route] + "_path", form_subject) )
263
+ completed = true
264
+ else
265
+ # render the next page
266
+ next_part = get_next_multipart_form_part(form_name, part)
267
+ # maybe pass in a route
268
+ redirect_to ( send(
269
+ self.multipart_forms[form_name][:form_route] + "_path",
270
+ :id => form_subject.id.to_s,
271
+ :multipart_form_part => next_part.to_s))
272
+ completed = false
273
+ end
274
+ return completed
275
+ end
276
+
277
+ # Gets the multipart form parts the user is allowed to directly link to
278
+ # with respect to the config information.
279
+ #
280
+ # If the config option show_incomplete_parts is set to false, do not return parts past the in_progress_form's last completed step
281
+ #
282
+ # @param [Symbol] form_name The name of the form
283
+ # @returns [Array] An array of form part symbols with no _update parts and other config restrictions
284
+ def get_available_multipart_form_parts(form_name, last_completed_part)
285
+ add_parts = true
286
+ parts = []
287
+ # loop over the parts
288
+ self.multipart_forms[form_name][:parts].each do |part|
289
+ if( add_parts && !part.match(/_update$/) )
290
+ parts << { :name => part, :number => parts.length + 1 }
291
+ end
292
+ if !ActsAsMultipartForm.config.show_incomplete_parts && part.to_s == last_completed_part.to_s
293
+ add_parts = false
294
+ end
295
+ end
296
+ return parts
297
+ end
298
+
299
+ end
300
+ end
301
+ end
@@ -0,0 +1,105 @@
1
+ module ActsAsMultipartForm
2
+ # Specify this to let the model know to expect multipart_form controller actions
3
+ # Allows the model to run conditional validations by giving access to methods
4
+ # with the form: multipart_form_name_multipart_controller_action.
5
+ #
6
+ # It includes support for multiple forms on a single controller by passing in an array of
7
+ # form symbols or a single symbol.
8
+ module MultipartFormInModel
9
+
10
+ def self.included(base)
11
+ base.extend ClassMethods
12
+ end
13
+
14
+ module ClassMethods
15
+ # Adds the information to the model needed to do conditional validations on the multipart forms
16
+ # Creates the multipart_forms field to store the list of forms the model has access to
17
+ # Creates the multipart_form_controller_action field to store the form the controller is currently on
18
+ # This is used for validations among other things
19
+ #
20
+ # @param [Hash] options A hash of symbols that represent multipart forms in the controller
21
+ def multipart_formable(*args)
22
+
23
+ mattr_accessor :multipart_form_controller_action unless self.respond_to?(:multipart_form_controller_action)
24
+ mattr_accessor :multipart_forms unless self.respond_to?(:multipart_forms)
25
+ self.multipart_forms = [] unless self.multipart_forms.is_a?(Array)
26
+ self.multipart_forms |= args[0][:forms]
27
+
28
+ # after save, the current controller action should not be set
29
+ after_save :reset_multipart_form_controller_action
30
+
31
+ include ActsAsMultipartForm::MultipartFormInModel::InstanceMethods
32
+ end
33
+ end
34
+
35
+ module InstanceMethods
36
+
37
+ # Sets the controller action to nil
38
+ # When we are not performing a save (or other action from a controller),
39
+ # the controller action should not be set
40
+ def reset_multipart_form_controller_action
41
+ self.multipart_form_controller_action = nil
42
+ end
43
+
44
+ # Determines whether multipart form controller is in use
45
+ # @returns [Boolean] True if both the multipart_forms and multipart_form_controller fields are set
46
+ def using_multipart_forms?
47
+ return(!self.multipart_forms.nil? && !self.multipart_form_controller_action.nil?)
48
+ end
49
+
50
+ # Overrides method missing to return true if the method is of the form
51
+ # multipart_form_name_multipart_controller_action
52
+ #
53
+ # If those conditions are not satisfied, called super
54
+ #
55
+ # @param [Symbol] sym The name of the method
56
+ # @param [Array[ args The arguments of the method
57
+ # @returns [Boolean] Whether or not the argument corresponds to a multipart form, otherwise super
58
+ def method_missing(sym, *args)
59
+ if multipart_form_method?(sym)
60
+ return multipart_form_controller_action?(sym)
61
+ else
62
+ super
63
+ end
64
+ end
65
+
66
+ # Overrides respond to to return true if the method is of the form
67
+ # multipart_form_name_multipart_controller_action
68
+ #
69
+ # If those conditions are not satisfied, called super
70
+ #
71
+ # @param [Symbol] sym The name of the method
72
+ # @param [Array[ args The arguments of the method
73
+ # @returns [Boolean] Whether or not the argument corresponds to a multipart form, otherwise super
74
+ def respond_to?(sym, *args)
75
+ if multipart_form_method?(sym)
76
+ return multipart_form_controller_action?(sym)
77
+ else
78
+ super
79
+ end
80
+ end
81
+
82
+ # determines whether the given method should be handled by the multipart form method handler
83
+ # based on whether it starts with the form name followed by an underscore
84
+ #
85
+ # @param [Symbol] sym Method to check
86
+ # @return [Boolean] Whether or not the symbol starts with one of the multipart forms
87
+ def multipart_form_method?(sym)
88
+ if self.multipart_forms
89
+ return self.multipart_forms.select {|form| sym.to_s =~ /^#{form}_/}.length > 0
90
+ end
91
+ return false
92
+ end
93
+
94
+ # Determines if the symbol corresponds to a multipart form action
95
+ # @param [Symbol] sym The name of the method
96
+ # @returns [Boolean] Whether or not the argument corresponds to a multipart form, otherwise super
97
+ def multipart_form_controller_action?(sym)
98
+ if using_multipart_forms?
99
+ return self.multipart_forms.select {|form| form.to_s + "_" + self.multipart_form_controller_action + "?" == sym.to_s}.length > 0
100
+ end
101
+ return false
102
+ end
103
+ end
104
+ end
105
+ end