hat-trick 0.0.1

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/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in hat-trick.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # Hat Trick
2
+ > Combines jQuery FormWizard, validation_group, and gon for the perfect triple-play of Rails wizarding.
3
+
4
+ ## Install
5
+ gem install hat-trick
6
+
7
+ ### Rails 3.2
8
+ (older versions not supported)
9
+
10
+ Put this in your Gemfile:
11
+
12
+ gem 'hat-trick'
13
+
14
+ ## Setup
15
+ In your controller:
16
+
17
+ wizard do
18
+ step :first_step
19
+ step :second_step
20
+ step :third_step
21
+ end
22
+
23
+ In your view:
24
+
25
+ <%= wizard_form_for @model do |f| %>
26
+ <fieldset id="first_step">...</fieldset>
27
+ <fieldset id="second_step">...</fieldset>
28
+ <fieldset id="third_step">...</fieldset>
29
+ <% end %>
30
+
31
+ The id's of the fieldsets in your form should match the step names you define in your controller.
32
+
33
+ ## Controlling the wizard flow
34
+ Sometimes you need to specify different paths through a wizard based on certain conditions. The way you do that with hat-trick is in the wizard DSL in the controller. Here are some examples:
35
+
36
+ Jumping to a step based on logged in status:
37
+
38
+ wizard do
39
+ step :first_step do
40
+ # after_this_step defines a callback to run after the current step is completed by the user
41
+ after_this_step do
42
+ # code in this block will be exec'd in the context of your controller
43
+ if user_signed_in?
44
+ next_step :third_step
45
+ end
46
+ end
47
+ end
48
+
49
+ step :second_step # wizard will go here after :first_step if user is not signed in
50
+
51
+ step :third_step # wizard will go here after :first_step if user is signed in
52
+
53
+ Repeating a previous step (for example, to show address sanitization results to the user):
54
+
55
+ wizard do
56
+ step :enter_address
57
+
58
+ step :confirm_santized_address do
59
+ repeat_step :enter_address
60
+ end
61
+
62
+ Skipping a step under certain conditions:
63
+
64
+ wizard do
65
+ step :first_step
66
+ step :second_step do
67
+ # before_this_step defines a callback to run before the user sees this step
68
+ before_this_step do
69
+ # code in this block will be exec'd in the context of your controller
70
+ skip_this_step unless foo.present?
71
+ end
72
+ end
73
+ end
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new('spec')
5
+
6
+ task :default => :spec
@@ -0,0 +1,233 @@
1
+ #= require vendor_js
2
+
3
+ class HatTrickWizard
4
+ constructor: (formElem, @wizard) ->
5
+ @form = $(formElem)
6
+ fieldsets = @form.find("fieldset")
7
+ fieldsets.addClass("step")
8
+ wizard_buttons = '<input type="reset" /><input type="submit" />'
9
+ fieldsets.find("div.buttons").html wizard_buttons
10
+ window.htData = {}
11
+ # prevent submitting the step that happens to be the last fieldset
12
+ this.addFakeLastStep()
13
+ this.enableFormwizard() # unless this.formwizardEnabled()
14
+ this.setCurrentStepField()
15
+ # TODO: Try this out instead of putting :start first
16
+ # this.showStep(@wizard.currentStep)
17
+ this.bindEvents()
18
+
19
+ buttons: {}
20
+
21
+ findStep: (stepId) ->
22
+ @form.find("fieldset##{stepId}")
23
+
24
+ createMethodField: (method) ->
25
+ """<input type="hidden" name="_method" value="#{method}" />"""
26
+
27
+ setAction: (url, method) ->
28
+ methodLower = method.toLowerCase()
29
+ console.log "Setting form action to #{methodLower} #{url}"
30
+ @form.attr("action", url)
31
+ @form.attr("method", "post")
32
+ methodField = @form.find('input[name="_method"]')
33
+ methodField.remove()
34
+ if methodLower isnt "post"
35
+ @form.prepend(this.createMethodField(method))
36
+
37
+ currentStepId: ->
38
+ @form.formwizard("state").currentStep
39
+
40
+ currentStep: ->
41
+ stepId = this.currentStepId()
42
+ this.findStep(stepId)
43
+
44
+ nextStepFieldHTML: """<input type="hidden" name="_ht_next_step" class="_ht_link" value="" />"""
45
+
46
+ fieldsets: ->
47
+ @form.find("fieldset")
48
+
49
+ ajaxEvents: (firstStep=false) ->
50
+ remoteAjax = {}
51
+ $fieldsets = this.fieldsets()
52
+ $fieldsets = $fieldsets.filter(":first") if firstStep
53
+ $fieldsets.each (index, element) =>
54
+ stepId = $(element).attr("id")
55
+ remoteAjax[stepId] = this.createAjaxEvent(stepId)
56
+ remoteAjax
57
+
58
+ createAjaxEvent: (step) ->
59
+ # console.log "Adding AJAX to step #{step}"
60
+ ajax =
61
+ url: @form.attr("action"),
62
+ dataType: "json",
63
+ beforeSubmit: (data) =>
64
+ console.log "Sending these data to the server: #{$.param(data)}"
65
+ success: (data) =>
66
+ console.log "Successful form POST; got #{$.param(data)}"
67
+ if data.wizardMetadata?
68
+ this.setAction(data.wizardMetadata.url, data.wizardMetadata.method)
69
+ # merge new data with window.htData
70
+ $.extend(window.htData, data)
71
+ error: (data) =>
72
+ appErrors = eval "(#{data.responseText})"
73
+ this.addErrorItem value[0] for key, value of appErrors.formModel
74
+ ajax
75
+
76
+ addErrorItem: (message) ->
77
+ $errorList = this.currentStep().find("ul.hat_trick_errors")
78
+ if $errorList.length > 0
79
+ $errorList.append("<li>#{message}</li>")
80
+ $errorList.show()
81
+
82
+ updateSteps: ->
83
+ @form.formwizard("update_steps")
84
+ @form.formwizard("option", remoteAjax: this.ajaxEvents())
85
+
86
+ goToStepId: (stepId) ->
87
+ console.log "Setting up goto #{stepId}"
88
+ this.setHTMeta("next_step", stepId)
89
+ @form.formwizard("next")
90
+
91
+ repeatStep: (step) ->
92
+ $sourceStep = this.findStep(step.repeatOf.fieldset)
93
+ console.log "Cloning repeated step #{step.repeatOf.fieldset}"
94
+ $clonedStep = $sourceStep.clone(true, true)
95
+ $clonedStep.css("display", "none")
96
+ $clonedStep.attr("id", step.name)
97
+ $sourceStep.after($clonedStep)
98
+ this.updateSteps()
99
+ @form.formwizard("show", step.name)
100
+
101
+ showStep: (step) ->
102
+ console.log "Showing step #{step.fieldset}"
103
+ @form.formwizard("show", step.fieldset)
104
+
105
+ formwizardEnabled: ->
106
+ @form.formwizard?
107
+
108
+ addFakeLastStep: ->
109
+ @form.append """<fieldset id="_ht_fake_last_step" style="display: none;" class="step"></fieldset>"""
110
+
111
+ enableFormwizard: ->
112
+ @form.formwizard
113
+ formPluginEnabled: true,
114
+ validationEnabled: true,
115
+ focusFirstInput: true,
116
+ historyEnabled: true,
117
+ disableUIStyles: true,
118
+ inDuration: 0,
119
+ linkClass: "_ht_link",
120
+ remoteAjax: this.ajaxEvents(true), # adds first Ajax event
121
+ formOptions:
122
+ success: (data) =>
123
+ console.log "Successful form POST"
124
+ beforeSubmit: (data) =>
125
+ console.log "Sending these data to the server: #{$.param(data)}"
126
+
127
+ htMetaHTML: (name) ->
128
+ """<input type="hidden" name="_ht_meta[#{name}]" id="_ht_#{name}" value="" />"""
129
+
130
+ setHTMeta: (key, value) ->
131
+ $meta = @form.find("input:hidden#_ht_#{key}")
132
+ if $meta.length is 0
133
+ $meta = @form.prepend(this.htMetaHTML(key)).find("#_ht_#{key}")
134
+ $meta.val(value)
135
+
136
+ clearHTMeta: (key) ->
137
+ @form.find("input:hidden#_ht_#{key}").remove()
138
+
139
+ setCurrentStepField: ->
140
+ stepId = this.currentStepId()
141
+ this.setHTMeta("step", stepId)
142
+ console.log "Current form step: #{stepId}"
143
+
144
+ clearNextStepField: ->
145
+ this.clearHTMeta("next_step")
146
+
147
+ fieldRegex: /^([^\[]+)\[([^\]]+)\]$/
148
+
149
+ setFieldValues: (formModel, selector, callback) ->
150
+ $currentStep = this.currentStep()
151
+ $currentStep.find(selector).each (index, element) =>
152
+ $element = $(element)
153
+ elementName = $element.attr("name")
154
+ if elementName? and elementName.search(@fieldRegex) isnt -1
155
+ [_, modelName, fieldName] = elementName.match(@fieldRegex)
156
+ if formModel[modelName]? and formModel[modelName][fieldName]?
157
+ fieldValue = formModel[modelName][fieldName]
158
+ callback($element, fieldValue) if fieldValue?
159
+
160
+ fillTextFields: (formModel) ->
161
+ this.setFieldValues formModel, "input:text", ($input, value) =>
162
+ $input.val(value)
163
+
164
+ setSelectFields: (formModel) ->
165
+ this.setFieldValues formModel, "select", ($select, value) =>
166
+ $select.find("option[value=\"#{value}\"]").attr("selected", "selected")
167
+
168
+ setCheckboxes: (formModel) ->
169
+ this.setFieldValues formModel, "input:checkbox", ($checkbox, value) =>
170
+ $checkbox.attr("checked", "checked") if value
171
+
172
+ setRadioButtons: (formModel) ->
173
+ this.setFieldValues formModel, "input:radio", ($radio, value) =>
174
+ $radio.find("[value=\"#{value}\"]").attr("checked", "checked")
175
+
176
+ setFormFields: (formModel) ->
177
+ this.fillTextFields(formModel)
178
+ this.setSelectFields(formModel)
179
+ this.setCheckboxes(formModel)
180
+ this.setRadioButtons(formModel)
181
+
182
+ createButton: (name, label) ->
183
+ """<input type="button" name="#{name}" value="#{label}" />"""
184
+
185
+ setButton: (name, label) ->
186
+ $buttonsDiv = this.currentStep().find("div.buttons")
187
+ switch name
188
+ when "next"
189
+ console.log "Setting submit button val to #{label}"
190
+ $buttonsDiv.find('input:submit').val(label)
191
+ when "back"
192
+ console.log "Setting reset button val to #{label}"
193
+ $buttonsDiv.find('input:reset').val(label)
194
+ else
195
+ buttonSelector = """input:button[name="#{name}"][value="#{label}"]"""
196
+ $existingButtons = $buttonsDiv.find(buttonSelector)
197
+ if $existingButtons.length == 0
198
+ console.log "Adding new #{name}:#{label} button"
199
+ $newButton = $buttonsDiv.append(this.createButton(name, label))
200
+ $newButton.click (event) =>
201
+ event.preventDefault()
202
+ this.goToStepId(name)
203
+
204
+ bindEvents: ->
205
+ @form.bind "step_shown", (event, data) =>
206
+ this.setCurrentStepField()
207
+ this.clearNextStepField()
208
+ this.setFormFields(htData.formModel)
209
+
210
+ buttons = this.buttons[this.currentStepId()]
211
+ if buttons?
212
+ this.setButton(name, label) for own name, label of buttons
213
+
214
+ if data.previousStep is data.firstStep
215
+ console.log "Adding additional Ajax events"
216
+ # adds additional Ajax events now that we have the update URL
217
+ @form.formwizard("option", remoteAjax: this.ajaxEvents())
218
+
219
+ @form.bind "after_remote_ajax", (event, data) =>
220
+ if htData.wizardMetadata?.currentStep.buttons?
221
+ stepId = htData.wizardMetadata.currentStep.fieldset
222
+ this.buttons[stepId] = htData.wizardMetadata.currentStep.buttons
223
+
224
+ if htData.wizardMetadata?.currentStep.repeatOf?
225
+ this.repeatStep(htData.wizardMetadata.currentStep)
226
+ else
227
+ this.showStep(htData.wizardMetadata.currentStep)
228
+
229
+ $ ->
230
+ $form = $("form.wizard")
231
+ if htData? and !htWizard?
232
+ console.log "Creating new HatTrickWizard instance"
233
+ window.htWizard = new HatTrickWizard($form, htData.wizardMetadata)
@@ -0,0 +1 @@
1
+ <%= include_gon(:namespace => 'htData', :camel_case => true) %>
data/hat-trick.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "hat_trick/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "hat-trick"
7
+ s.version = HatTrick::VERSION
8
+ s.authors = ["Wes Morgan"]
9
+ s.email = ["cap10morgan@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{Rails wizards done right}
12
+ s.description = %q{Combines jQuery FormWizard, validation_group, and gon for the perfect triple-play of Rails wizarding.}
13
+
14
+ s.rubyforge_project = "hat-trick"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_development_dependency "rspec"
22
+ s.add_development_dependency "mocha"
23
+ s.add_development_dependency "debugger"
24
+
25
+ s.add_runtime_dependency "rails", "~> 3.1"
26
+ s.add_runtime_dependency "validation_group"
27
+ s.add_runtime_dependency "gon"
28
+ end
data/lib/hat-trick.rb ADDED
@@ -0,0 +1,8 @@
1
+ require "hat_trick/version"
2
+ require "active_support"
3
+ require "active_support/core_ext/module"
4
+ require "hat_trick/rails_engine"
5
+ require "hat_trick/dsl"
6
+ require "gon"
7
+
8
+ ::ActionController::Base.send(:include, HatTrick::DSL)
@@ -0,0 +1,118 @@
1
+ require 'hat_trick/model_methods'
2
+
3
+ module HatTrick
4
+ module ControllerHooks
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ alias_method_chain :render, :hat_trick
9
+ end
10
+
11
+ def self.def_action_method_aliases(action_methods)
12
+ action_methods.each do |meth|
13
+ Rails.logger.info "Aliasing #{meth}"
14
+ module_eval <<-RUBY_EVAL
15
+ def #{meth}_with_hat_trick(*args)
16
+ Rails.logger.info "#{meth}_with_hat_trick called"
17
+ #{meth}_hook(*args) if respond_to?("#{meth}_hook", :include_private)
18
+ common_hook(*args)
19
+ #{meth}_without_hat_trick(*args)
20
+ end
21
+ private "#{meth}_with_hat_trick"
22
+ RUBY_EVAL
23
+ end
24
+ true
25
+ end
26
+
27
+ private
28
+
29
+ def params_model_name
30
+ params.each do |k,v|
31
+ return class_name(k) if v.is_a?(Hash) && is_model?(k)
32
+ end
33
+ nil
34
+ end
35
+
36
+ def is_model?(model_name)
37
+ begin
38
+ class_name(model_name).constantize
39
+ rescue NameError
40
+ return false
41
+ end
42
+ true
43
+ end
44
+
45
+ def class_name(hash_key)
46
+ hash_key.to_s.camelize
47
+ end
48
+
49
+ def model_class
50
+ model_name = params_model_name
51
+ return nil if model_name.nil?
52
+ begin
53
+ model_class = params_model_name.constantize
54
+ rescue NameError
55
+ Rails.logger.error "Could not find model class #{params_model_name.camelize}"
56
+ nil
57
+ else
58
+ model_class
59
+ end
60
+ end
61
+
62
+ def setup_validation_group_for(wizard_step)
63
+ klass = model_class
64
+ return if klass.nil?
65
+ step_name = wizard_step.name
66
+ validation_groups = ::ActiveRecord::Base.validation_group_classes[klass] || []
67
+ unless validation_groups.include?(step_name)
68
+ klass.validation_group(step_name, :fields => params.keys)
69
+ end
70
+ HatTrick::ModelMethods.set_current_validation_group_for(model_class, step_name)
71
+ unless klass.included_modules.include?(HatTrick::ModelMethods)
72
+ klass.send(:include, HatTrick::ModelMethods)
73
+ end
74
+ end
75
+
76
+ def create_hook(*args)
77
+ setup_validation_group_for(ht_wizard.current_step)
78
+ end
79
+
80
+ def update_hook(*args)
81
+ setup_validation_group_for(ht_wizard.current_step)
82
+ end
83
+
84
+ def common_hook(*args)
85
+ # nothing here for now
86
+ end
87
+
88
+ def render_with_hat_trick(*args)
89
+ if args.first.has_key?(:json)
90
+ model = args[0][:json]
91
+ ht_wizard.model = model
92
+ end
93
+
94
+ if params.has_key?('_ht_meta')
95
+ next_step = params['_ht_meta']['next_step']
96
+ ht_wizard.advance_step(next_step)
97
+ end
98
+
99
+ wizard_metadata = {
100
+ :url => ht_wizard.current_form_url,
101
+ :method => ht_wizard.current_form_method,
102
+ :currentStep => ht_wizard.current_step,
103
+ }
104
+
105
+ # this sets the wizard_metadata for the initial page load
106
+ gon.wizard_metadata = wizard_metadata
107
+
108
+ if ht_wizard.model && args[0].has_key?(:json)
109
+ # this sets the wizard metadata for subsequent AJAX requests
110
+ args[0][:json] = { :formModel => ht_wizard.model,
111
+ :wizardMetadata => wizard_metadata }
112
+ args[0][:json].merge! ht_wizard.include_data
113
+ end
114
+
115
+ render_without_hat_trick(*args)
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,123 @@
1
+ require 'hat_trick/wizard_definition'
2
+ require 'hat_trick/controller_hooks'
3
+
4
+ module HatTrick
5
+ module DSL
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+ def wizard(&block)
10
+ if block_given?
11
+ include HatTrick::DSL::ControllerInstanceMethods
12
+ include HatTrick::ControllerHooks
13
+
14
+ @wizard_def = HatTrick::WizardDefinition.new
15
+
16
+ @wizard_dsl = HatTrick::DSL::WizardContext.new(@wizard_def)
17
+ @wizard_dsl.instance_eval &block
18
+
19
+ else
20
+ raise ArgumentError, "wizard called without a block"
21
+ end
22
+ end
23
+ end
24
+
25
+ module ControllerInstanceMethods
26
+ extend ActiveSupport::Concern
27
+
28
+ included do
29
+ before_filter :setup_wizard
30
+ end
31
+
32
+ private
33
+
34
+ attr_reader :ht_wizard
35
+
36
+ def setup_wizard
37
+ wizard_def = self.class.instance_variable_get("@wizard_def")
38
+ @ht_wizard = wizard_def.get_wizard(self)
39
+
40
+ if params.has_key?('_ht_meta')
41
+ step_name = params['_ht_meta']['step']
42
+ @ht_wizard.current_step = step_name if step_name
43
+ end
44
+ end
45
+ end
46
+
47
+ class WizardContext
48
+ attr_reader :wizard_def
49
+ attr_accessor :wizard
50
+
51
+ delegate :model, :previously_visited_step, :to => :wizard
52
+
53
+ def initialize(wizard_def)
54
+ @wizard_def = wizard_def
55
+ end
56
+
57
+ def step(name, args={}, &block)
58
+ wizard_def.add_step(name, args)
59
+ instance_eval &block if block_given?
60
+ end
61
+
62
+ def next_step(name=nil)
63
+ if name.nil?
64
+ wizard.next_step
65
+ else
66
+ raise "next_step should only be called from an after block" if wizard.nil?
67
+ step = wizard.find_step(name)
68
+ wizard.current_step.next_step = step
69
+ end
70
+ end
71
+
72
+ def repeat_step(name)
73
+ repeated_step = wizard_def.find_step(name)
74
+ raise ArgumentError, "Couldn't find step named #{name}" unless repeated_step
75
+ new_step = repeated_step.dup
76
+ # use the repeated step's fieldset id
77
+ new_step.fieldset = repeated_step.fieldset
78
+ # but use the current step's name
79
+ new_step.name = wizard_def.last_step.name
80
+ if wizard
81
+ # TODO: Might turn all these into run-time methods; which would get
82
+ # rid of this wizard / wizard_def distinction
83
+ else
84
+ # replace the step we're in the middle of defining w/ new_step
85
+ wizard_def.replace_step(wizard_def.last_step, new_step)
86
+ end
87
+ end
88
+
89
+ def skip_this_step
90
+ if wizard
91
+ wizard.skip_step(wizard.current_step)
92
+ else
93
+ # skip_this_step in wizard definition context means the step
94
+ # can be explicitly jumped to, but won't be in the normal flow
95
+ wizard_def.last_step.skipped = true
96
+ end
97
+ end
98
+
99
+ def button_to(name, options=nil)
100
+ if wizard
101
+ raise "button_to not yet supported in before/after blocks"
102
+ end
103
+ label = options[:label] if options
104
+ label ||= name.to_s.humanize
105
+ step = wizard_def.last_step
106
+ step.buttons = step.buttons.merge(name => label)
107
+ end
108
+
109
+ def before(&block)
110
+ wizard_def.last_step.before_callback = block
111
+ end
112
+
113
+ def after(&block)
114
+ wizard_def.last_step.after_callback = block
115
+ end
116
+
117
+ def include_data(key, &block)
118
+ wizard_def.last_step.include_data = { key.to_sym => block }
119
+ end
120
+ end
121
+ end
122
+ end
123
+
@@ -0,0 +1,30 @@
1
+ module HatTrick
2
+ module FormHelper
3
+ def wizard_form_for(record, *args, &proc)
4
+ options = args.extract_options!
5
+ options[:html] = { :class => 'wizard' }
6
+
7
+ wizard = controller.send(:ht_wizard)
8
+ wizard.start unless wizard.started?
9
+
10
+ # Do we still need these 2 lines?
11
+ wizard.model = record
12
+ controller.gon.form_model = record
13
+
14
+ options[:url] = wizard.current_form_url
15
+ options[:method] = wizard.current_form_method.to_sym
16
+
17
+ output = ActiveSupport::SafeBuffer.new
18
+ output.safe_concat(wizard_partial)
19
+
20
+ # now run the default FormBuilder & append to output
21
+ output << self.form_for(record, *(args << options), &proc)
22
+ end
23
+
24
+ private
25
+
26
+ def wizard_partial
27
+ controller.render_to_string(:partial => 'hat_trick/wizard_meta')
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,24 @@
1
+ module HatTrick
2
+ module ModelMethods
3
+ extend ActiveSupport::Concern
4
+ mattr_accessor :current_validation_group
5
+
6
+ included do
7
+ alias_method_chain :save, :hat_trick
8
+ end
9
+
10
+ def self.set_current_validation_group_for(klass, validation_group_name)
11
+ self.current_validation_group ||= {}
12
+ current_validation_group[klass.to_s.underscore] = validation_group_name
13
+ end
14
+
15
+ def self.current_validation_group_for(klass)
16
+ current_validation_group[klass.to_s.underscore]
17
+ end
18
+
19
+ def save_with_hat_trick(*args)
20
+ enable_validation_group HatTrick::ModelMethods.current_validation_group_for(self.class)
21
+ save_without_hat_trick(*args)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,13 @@
1
+ require 'hat_trick/form_helper'
2
+
3
+ module HatTrick
4
+ class RailsEngine < ::Rails::Engine
5
+ # just defining this causes Rails to look for assets inside this gem
6
+
7
+ initializer 'hat-trick.form_helpers' do
8
+ ActiveSupport.on_load(:action_view) do
9
+ include HatTrick::FormHelper
10
+ end
11
+ end
12
+ end
13
+ end