Customization » History » Version 8
Phil Hodgson, 05/22/2014 01:16 PM
1 | 1 | Phil Hodgson | h1. Customization |
---|---|---|---|
2 | |||
3 | 6 | Phil Hodgson | h2. Enabling and Disabling "Sections" of Tapestry |
4 | |||
5 | Tapestry has been divided into a handful of logical "sections". To date, they are: |
||
6 | |||
7 | * Section::SIGNUP |
||
8 | * Section::PUBLIC_DATA |
||
9 | 8 | Phil Hodgson | * Section::PUBLIC_PROFILE |
10 | 6 | Phil Hodgson | * Section::ENROLL |
11 | * Section::GOOGLE_SURVEYS |
||
12 | * Section::SAMPLES |
||
13 | |||
14 | In your @config.yml@ file you can specify an array of these and assign it to the @enabled_sections@ config parameter. An example is in the @config.defaults.yml@, where only @Section::SIGNUP@ is enabled by default. |
||
15 | |||
16 | Furthermore, in your overridden views, partials, etc. (see section below) you can use embedded Ruby to access which sections are enabled with the @include_section?@ helper method. Search in the source code for examples. |
||
17 | |||
18 | 1 | Phil Hodgson | h2. Overriding Default Views, Partials, Templates, etc. |
19 | 2 | Phil Hodgson | |
20 | It is possible to override any Rails view in the application by mimicking the directory structure in @app/views@ but under another folder @site_specific/app/views@. For example, to use your own version of @_dashboard.html.erb@ in @app/views/pages@ you would put it in @site_specific/app/views/pages@. |
||
21 | 1 | Phil Hodgson | |
22 | 6 | Phil Hodgson | You can override the @#{Rails.root}/site_specific@ folder itself with the environment variable @TAPESTRY_OVERRIDE_PATH@, so that the folder can be left entirely outside of the Tapestry code base. |
23 | 2 | Phil Hodgson | |
24 | It is important to understand that including this folder, any subfolders, and all files is _optional_. If you do not wish to override a particular view, leave it out of the override folder. |
||
25 | 3 | Phil Hodgson | |
26 | h3. Caveat |
||
27 | |||
28 | _This statement to be followed up after more investigation._ |
||
29 | |||
30 | It is my impression that when using multiple paths that the technique of using @explicitly_unloadable_constants@ for having files reload without restarting the server will not work properly. This could mean that while developing these site-specific files that the server has to be restarted after each change. |
||
31 | |||
32 | h3. Overriding @lib@ Files |
||
33 | |||
34 | The same logic works for files in the override path under the @lib@ subfolder, i.e. either @#{Rails.root}/site_specific/lib@ or @#{ENV['TAPESTRY_OVERRIDE_PATH']}/lib@. |
||
35 | |||
36 | h2. Adding Custom Questions to the "Participation Consent" Form |
||
37 | |||
38 | Currently this text and form are found in @views/participation_consents/show.html.erb@. This currently saves the user's responses in the InformedConsentResponse model. There is in this model a field called "other_answers" that is a serialized Hash where any number of "dynamically defined" answers can be saved with keys of your choosing. To accomplish this you have to add form inputs that end up with a @name@ attribute that looks like (e.g. to record "age"): @other_answers[age]@ and it will be recorded in the "other_answers" Hash in the model under the :age key. |
||
39 | |||
40 | There is a view helper for creating radio boxes for the participation concept form using this "other_answers" field. Example: |
||
41 | |||
42 | <pre> |
||
43 | <div class="consent-form-question"> |
||
44 | <p> |
||
45 | Would you judge yourself to be sane? |
||
46 | <%= radio_answers( 'sanity', [['0', 'No'], |
||
47 | ['1', 'Sometimes'], |
||
48 | ['2', 'Yes']] ) %> |
||
49 | </p> |
||
50 | </div> |
||
51 | </pre> |
||
52 | |||
53 | 4 | Phil Hodgson | There are also helpers for text areas (@text_area_answer@) and standard input texts (@text_field_answer@). For example: |
54 | 3 | Phil Hodgson | |
55 | 4 | Phil Hodgson | <pre> |
56 | <div class="consent-form-question"> |
||
57 | <p> |
||
58 | If sane only sometimes, please explain when and for what reason this occurs: |
||
59 | </p> |
||
60 | <p> |
||
61 | <%= text_area_answer 'reason_sometimes_sane', { :cols => 60, :rows => 3 } %> |
||
62 | </p> |
||
63 | </div> |
||
64 | </pre> |
||
65 | |||
66 | |||
67 | 3 | Phil Hodgson | h3. Adding Custom Validation of Your Custom Question |
68 | 1 | Phil Hodgson | |
69 | 4 | Phil Hodgson | This is done by adding a site-specific validations file in the @lib@ "override" folder, in the @lib/site_specific/validations.rb@ module. First place the following code in the file: |
70 | 3 | Phil Hodgson | |
71 | 1 | Phil Hodgson | <pre> |
72 | 4 | Phil Hodgson | module SiteSpecific |
73 | module Validations |
||
74 | extend ActiveSupport::Concern |
||
75 | |||
76 | # *Do not remove this +included+ block!* It is what works the magic. |
||
77 | included do |
||
78 | method_name = "#{self.name.to_s.underscore}_validations" |
||
79 | validate method_name if method_defined? method_name |
||
80 | end |
||
81 | |||
82 | end |
||
83 | end |
||
84 | </pre> |
||
85 | |||
86 | Then after this insert a method called @informed_consent_response_validations@ (after the name of the model relevant to the Participation Consent form). You can check @other_answers@ and add errors in the standard ActiveRecord way. For example: |
||
87 | |||
88 | <pre> |
||
89 | 1 | Phil Hodgson | def informed_consent_response_validations |
90 | 4 | Phil Hodgson | case self.other_answers[:sanity] |
91 | when '2' |
||
92 | 1 | Phil Hodgson | errors.add( :other_answers, :sanity_not_permitted) |
93 | 4 | Phil Hodgson | when '1' |
94 | if self.other_answers[:reason_sometimes_sane].blank? |
||
95 | errors.add( :other_answers, :explain_occasional_sanity ) |
||
96 | end |
||
97 | 3 | Phil Hodgson | end |
98 | 1 | Phil Hodgson | end |
99 | 3 | Phil Hodgson | </pre> |
100 | |||
101 | 4 | Phil Hodgson | The messages should be placed in your locale file under: |
102 | 3 | Phil Hodgson | |
103 | <pre> |
||
104 | en: |
||
105 | activerecord: |
||
106 | errors: |
||
107 | 1 | Phil Hodgson | models: |
108 | informed_consent_response: |
||
109 | attributes: |
||
110 | other_answers: |
||
111 | 4 | Phil Hodgson | sanity_not_permitted: |
112 | You are not permitted to be sane. |
||
113 | explain_occasional_sanity: |
||
114 | Please explain when and why you are sometimes sane. |
||
115 | 3 | Phil Hodgson | </pre> |
116 | 4 | Phil Hodgson | |
117 | 1 | Phil Hodgson | See the documentation on [[Internationalization]] for where to put this. |
118 | 6 | Phil Hodgson | |
119 | h2. Overriding the Validations on Any Model |
||
120 | |||
121 | The above section explaining how to override validations for the @InformedConsentResponse@ model can serve as an example for the general case. There is only one change required to the Tapestry source code base. In general, this is discouraged, so you should consider contacting the Tapestry development team and letting them know that you've found a need to override validation on a particular model, but the change is slight and easy to deal with in future merges. Basically, you must insert, _after any model validations_, the following line: |
||
122 | |||
123 | <pre> |
||
124 | include SiteSpecific::Validations rescue {} |
||
125 | </pre> |
||
126 | |||
127 | If you do not insert this line after any of the model validations already present in the model class, you will not be able to override them. An example is already in the model for ShippingAddress (@app/models/shipping_address.rb@), where a site may want to allow specifying "State" to be optional: |
||
128 | |||
129 | <pre> |
||
130 | validates_presence_of :user_id |
||
131 | validates_presence_of :address_line_1 |
||
132 | validates_presence_of :city |
||
133 | validates_presence_of :state |
||
134 | validates_presence_of :zip |
||
135 | validates_presence_of :phone |
||
136 | |||
137 | include SiteSpecific::Validations rescue {} |
||
138 | </pre> |
||
139 | |||
140 | Note that the @include@ is _after_ the list of @validates_presence_of@ directives. This allows any of those validations to be effectively reversed. So, in your site-specific override folder, in your @lib/site_specific/validations.rb@ file (also see example above for Consent Questions), you would simply add the following method: |
||
141 | |||
142 | <pre> |
||
143 | def shipping_address_validations |
||
144 | # allow invalid "state" field |
||
145 | errors.delete(:state) |
||
146 | end |
||
147 | </pre> |
||
148 | 5 | Phil Hodgson | |
149 | 7 | Phil Hodgson | To remove the State field from the user interface entirely you'l also want to remove it from the relevant view, which for ShippingAddress is the partial in your site-override folder under @app/views/shipping_addresses/_form.html.erb@. Simply copy the @_form.html.erb@ file from the original source code tree and then *remove* the following lines: |
150 | |||
151 | <pre> |
||
152 | <div class="field"> |
||
153 | <span style="color: red"> * </span><%= f.label :state %><br /> |
||
154 | <%= f.state_select(:state, 'US', {:include_blank => "Select a State", :selected => @shipping_address.state }, { :style => "width: 230px;"}) -%> |
||
155 | </div> |
||
156 | </pre> |
||
157 | |||
158 | Or remove the @<span style="color: red"> * </span>@ to show it as non-mandatory. (For information on the @state_select@ method, see the documentation for the @carmen@ gem.) |
||
159 | |||
160 | 5 | Phil Hodgson | h4. Automatic Reloading of the Validations Override During Development |
161 | |||
162 | As shown in the @development.rb.example@ file, you can add the following line to your @development.rb@ to have validation override changes automatically reload without having to restart your Rails server: |
||
163 | |||
164 | <pre> |
||
165 | ActiveSupport::Dependencies.explicitly_unloadable_constants << 'SiteSpecific::Validations' |
||
166 | </pre> |