magic_userstamp 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/.gitignore +5 -0
  2. data/CHANGELOG +26 -0
  3. data/LICENSE +20 -0
  4. data/README.original +179 -0
  5. data/README.rdoc +64 -0
  6. data/Rakefile +45 -0
  7. data/VERSION +1 -0
  8. data/init.rb +12 -0
  9. data/lib/userstamp/config.rb +119 -0
  10. data/lib/userstamp/controller.rb +43 -0
  11. data/lib/userstamp/event.rb +63 -0
  12. data/lib/userstamp/magic_columns.rb +49 -0
  13. data/lib/userstamp/migration_helper.rb +17 -0
  14. data/lib/userstamp/stampable.rb +147 -0
  15. data/lib/userstamp/stamper.rb +41 -0
  16. data/lib/userstamp.rb +17 -0
  17. data/magic_userstamp.gemspec +124 -0
  18. data/rdoc/classes/Ddb/Controller/Userstamp/InstanceMethods.html +105 -0
  19. data/rdoc/classes/Ddb/Controller/Userstamp.html +125 -0
  20. data/rdoc/classes/Ddb/Controller.html +111 -0
  21. data/rdoc/classes/Ddb/Userstamp/MigrationHelper/InstanceMethods.html +142 -0
  22. data/rdoc/classes/Ddb/Userstamp/MigrationHelper.html +111 -0
  23. data/rdoc/classes/Ddb/Userstamp/Stampable/ClassMethods.html +222 -0
  24. data/rdoc/classes/Ddb/Userstamp/Stampable.html +128 -0
  25. data/rdoc/classes/Ddb/Userstamp/Stamper/ClassMethods.html +142 -0
  26. data/rdoc/classes/Ddb/Userstamp/Stamper/InstanceMethods.html +207 -0
  27. data/rdoc/classes/Ddb/Userstamp/Stamper.html +112 -0
  28. data/rdoc/classes/Ddb/Userstamp.html +121 -0
  29. data/rdoc/created.rid +1 -0
  30. data/rdoc/files/CHANGELOG.html +137 -0
  31. data/rdoc/files/LICENSE.html +129 -0
  32. data/rdoc/files/README.html +341 -0
  33. data/rdoc/files/lib/migration_helper_rb.html +101 -0
  34. data/rdoc/files/lib/stampable_rb.html +101 -0
  35. data/rdoc/files/lib/stamper_rb.html +101 -0
  36. data/rdoc/files/lib/userstamp_rb.html +101 -0
  37. data/rdoc/fr_class_index.html +37 -0
  38. data/rdoc/fr_file_index.html +33 -0
  39. data/rdoc/fr_method_index.html +33 -0
  40. data/rdoc/index.html +24 -0
  41. data/rdoc/rdoc-style.css +208 -0
  42. data/spec/compatibility_stamping_spec.rb +76 -0
  43. data/spec/config_spec.rb +155 -0
  44. data/spec/database.yml +4 -0
  45. data/spec/fixtures/comments.yml +16 -0
  46. data/spec/fixtures/people.yml +11 -0
  47. data/spec/fixtures/posts.yml +9 -0
  48. data/spec/fixtures/users.yml +7 -0
  49. data/spec/magic_column_spec.rb +171 -0
  50. data/spec/posts_controller_spec.rb +41 -0
  51. data/spec/resources/controllers/application_controller.rb +2 -0
  52. data/spec/resources/controllers/posts_controller.rb +26 -0
  53. data/spec/resources/controllers/users_controller.rb +12 -0
  54. data/spec/resources/controllers/userstamp_controller.rb +9 -0
  55. data/spec/resources/models/comment.rb +4 -0
  56. data/spec/resources/models/person.rb +4 -0
  57. data/spec/resources/models/ping.rb +7 -0
  58. data/spec/resources/models/post.rb +4 -0
  59. data/spec/resources/models/user.rb +4 -0
  60. data/spec/schema.rb +56 -0
  61. data/spec/spec.opts +6 -0
  62. data/spec/spec_helper.rb +66 -0
  63. data/spec/stamping_spec.rb +114 -0
  64. data/spec/users_controller_spec.rb +33 -0
  65. metadata +145 -0
@@ -0,0 +1,137 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+
6
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
7
+ <head>
8
+ <title>File: CHANGELOG</title>
9
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10
+ <meta http-equiv="Content-Script-Type" content="text/javascript" />
11
+ <link rel="stylesheet" href=".././rdoc-style.css" type="text/css" media="screen" />
12
+ <script type="text/javascript">
13
+ // <![CDATA[
14
+
15
+ function popupCode( url ) {
16
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
17
+ }
18
+
19
+ function toggleCode( id ) {
20
+ if ( document.getElementById )
21
+ elem = document.getElementById( id );
22
+ else if ( document.all )
23
+ elem = eval( "document.all." + id );
24
+ else
25
+ return false;
26
+
27
+ elemStyle = elem.style;
28
+
29
+ if ( elemStyle.display != "block" ) {
30
+ elemStyle.display = "block"
31
+ } else {
32
+ elemStyle.display = "none"
33
+ }
34
+
35
+ return true;
36
+ }
37
+
38
+ // Make codeblocks hidden by default
39
+ document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
40
+
41
+ // ]]>
42
+ </script>
43
+
44
+ </head>
45
+ <body>
46
+
47
+
48
+
49
+ <div id="fileHeader">
50
+ <h1>CHANGELOG</h1>
51
+ <table class="header-table">
52
+ <tr class="top-aligned-row">
53
+ <td><strong>Path:</strong></td>
54
+ <td>CHANGELOG
55
+ </td>
56
+ </tr>
57
+ <tr class="top-aligned-row">
58
+ <td><strong>Last Update:</strong></td>
59
+ <td>Sat Apr 05 11:41:29 -0600 2008</td>
60
+ </tr>
61
+ </table>
62
+ </div>
63
+ <!-- banner header -->
64
+
65
+ <div id="bodyContent">
66
+
67
+
68
+
69
+ <div id="contextContent">
70
+
71
+ <div id="description">
72
+ <p>
73
+ 2.0 (2-17-2008)
74
+ </p>
75
+ <pre>
76
+ * [Ben Wyrosdick] - Added a migration helper that gives migration scripts a &lt;tt&gt;userstamps&lt;/tt&gt;
77
+ method.
78
+ * [Marshall Roch] - Stamping can be temporarily turned off using the 'without_stamps' class
79
+ method.
80
+ Example:
81
+ Post.without_stamps do
82
+ post = Post.find(params[:id])
83
+ post.update_attributes(params[:post])
84
+ post.save
85
+ end
86
+
87
+ * Models that should receive updates made by 'stampers' now use the acts_as_stampable class
88
+ method. This sets up the belongs_to relationships and also injects private methods for use by
89
+ the individual callback filter methods.
90
+
91
+ * Models that are responsible for updating now use the acts_as_stamper class method. This
92
+ injects the stamper= and stamper methods that are thread safe and should be updated per
93
+ request by a controller.
94
+
95
+ * The Userstamp module is now meant to be included with one of your project's controllers (the
96
+ Application Controller is recommended). It creates a before filter called 'set_stampers' that
97
+ is responsible for setting all the current Stampers.
98
+ </pre>
99
+ <p>
100
+ 1.0 (01-18-2006)
101
+ </p>
102
+ <pre>
103
+ * Initial Release
104
+ </pre>
105
+
106
+ </div>
107
+
108
+
109
+ </div>
110
+
111
+
112
+ </div>
113
+
114
+
115
+ <!-- if includes -->
116
+
117
+ <div id="section">
118
+
119
+
120
+
121
+
122
+
123
+
124
+
125
+
126
+ <!-- if method_list -->
127
+
128
+
129
+ </div>
130
+
131
+
132
+ <div id="validator-badges">
133
+ <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
134
+ </div>
135
+
136
+ </body>
137
+ </html>
@@ -0,0 +1,129 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+
6
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
7
+ <head>
8
+ <title>File: LICENSE</title>
9
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10
+ <meta http-equiv="Content-Script-Type" content="text/javascript" />
11
+ <link rel="stylesheet" href=".././rdoc-style.css" type="text/css" media="screen" />
12
+ <script type="text/javascript">
13
+ // <![CDATA[
14
+
15
+ function popupCode( url ) {
16
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
17
+ }
18
+
19
+ function toggleCode( id ) {
20
+ if ( document.getElementById )
21
+ elem = document.getElementById( id );
22
+ else if ( document.all )
23
+ elem = eval( "document.all." + id );
24
+ else
25
+ return false;
26
+
27
+ elemStyle = elem.style;
28
+
29
+ if ( elemStyle.display != "block" ) {
30
+ elemStyle.display = "block"
31
+ } else {
32
+ elemStyle.display = "none"
33
+ }
34
+
35
+ return true;
36
+ }
37
+
38
+ // Make codeblocks hidden by default
39
+ document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
40
+
41
+ // ]]>
42
+ </script>
43
+
44
+ </head>
45
+ <body>
46
+
47
+
48
+
49
+ <div id="fileHeader">
50
+ <h1>LICENSE</h1>
51
+ <table class="header-table">
52
+ <tr class="top-aligned-row">
53
+ <td><strong>Path:</strong></td>
54
+ <td>LICENSE
55
+ </td>
56
+ </tr>
57
+ <tr class="top-aligned-row">
58
+ <td><strong>Last Update:</strong></td>
59
+ <td>Tue Mar 11 20:24:59 -0600 2008</td>
60
+ </tr>
61
+ </table>
62
+ </div>
63
+ <!-- banner header -->
64
+
65
+ <div id="bodyContent">
66
+
67
+
68
+
69
+ <div id="contextContent">
70
+
71
+ <div id="description">
72
+ <p>
73
+ Copyright (c) 2006-2008 DeLynn Berry
74
+ </p>
75
+ <p>
76
+ Permission is hereby granted, free of charge, to any person obtaining a
77
+ copy of this software and associated documentation files (the
78
+ &quot;Software&quot;), to deal in the Software without restriction,
79
+ including without limitation the rights to use, copy, modify, merge,
80
+ publish, distribute, sublicense, and/or sell copies of the Software, and to
81
+ permit persons to whom the Software is furnished to do so, subject to the
82
+ following conditions:
83
+ </p>
84
+ <p>
85
+ The above copyright notice and this permission notice shall be included in
86
+ all copies or substantial portions of the Software.
87
+ </p>
88
+ <p>
89
+ THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND,
90
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
91
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
92
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
93
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
94
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
95
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
96
+ </p>
97
+
98
+ </div>
99
+
100
+
101
+ </div>
102
+
103
+
104
+ </div>
105
+
106
+
107
+ <!-- if includes -->
108
+
109
+ <div id="section">
110
+
111
+
112
+
113
+
114
+
115
+
116
+
117
+
118
+ <!-- if method_list -->
119
+
120
+
121
+ </div>
122
+
123
+
124
+ <div id="validator-badges">
125
+ <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
126
+ </div>
127
+
128
+ </body>
129
+ </html>
@@ -0,0 +1,341 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+
6
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
7
+ <head>
8
+ <title>File: README</title>
9
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10
+ <meta http-equiv="Content-Script-Type" content="text/javascript" />
11
+ <link rel="stylesheet" href=".././rdoc-style.css" type="text/css" media="screen" />
12
+ <script type="text/javascript">
13
+ // <![CDATA[
14
+
15
+ function popupCode( url ) {
16
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
17
+ }
18
+
19
+ function toggleCode( id ) {
20
+ if ( document.getElementById )
21
+ elem = document.getElementById( id );
22
+ else if ( document.all )
23
+ elem = eval( "document.all." + id );
24
+ else
25
+ return false;
26
+
27
+ elemStyle = elem.style;
28
+
29
+ if ( elemStyle.display != "block" ) {
30
+ elemStyle.display = "block"
31
+ } else {
32
+ elemStyle.display = "none"
33
+ }
34
+
35
+ return true;
36
+ }
37
+
38
+ // Make codeblocks hidden by default
39
+ document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
40
+
41
+ // ]]>
42
+ </script>
43
+
44
+ </head>
45
+ <body>
46
+
47
+
48
+
49
+ <div id="fileHeader">
50
+ <h1>README</h1>
51
+ <table class="header-table">
52
+ <tr class="top-aligned-row">
53
+ <td><strong>Path:</strong></td>
54
+ <td>README
55
+ </td>
56
+ </tr>
57
+ <tr class="top-aligned-row">
58
+ <td><strong>Last Update:</strong></td>
59
+ <td>Sat Apr 05 15:01:24 -0600 2008</td>
60
+ </tr>
61
+ </table>
62
+ </div>
63
+ <!-- banner header -->
64
+
65
+ <div id="bodyContent">
66
+
67
+
68
+
69
+ <div id="contextContent">
70
+
71
+ <div id="description">
72
+ <h1>Userstamp Plugin (v 2.0)</h1>
73
+ <h2>Overview</h2>
74
+ <p>
75
+ The Userstamp Plugin extends <a
76
+ href="http://api.rubyonrails.com/classes/ActiveRecord/Base.html">ActiveRecord::Base</a>
77
+ to add automatic updating of &#8216;creator&#8217;, &#8216;updater&#8217;,
78
+ and &#8216;deleter&#8217; attributes. It is based loosely on the <a
79
+ href="http://api.rubyonrails.com/classes/ActiveRecord/Timestamp.html">ActiveRecord::Timestamp</a>
80
+ module.
81
+ </p>
82
+ <p>
83
+ Two class methods (<tt>model_stamper</tt> and <tt>stampable</tt>) are
84
+ implemented in this plugin. The <tt>model_stamper</tt> method is used in
85
+ models that are responsible for creating, updating, or deleting other
86
+ objects. The <tt>stampable</tt> method is used in models that are subject
87
+ to being created, updated, or deleted by &#8216;stampers&#8217;.
88
+ </p>
89
+ <h2>Installation</h2>
90
+ <p>
91
+ Installation of the plugin can be done using the built in Rails plugin
92
+ script. Issue the following command from the root of your application:
93
+ </p>
94
+ <pre>
95
+ script/plugin install git://github.com/delynn/userstamp.git
96
+ </pre>
97
+ <p>
98
+ Once installed you will need to restart your application for the plugin to
99
+ be loaded into the Rails environment.
100
+ </p>
101
+ <p>
102
+ You might also be interested in using <a
103
+ href="http://piston.rubyforge.org/index.html">Piston</a> to manage the
104
+ importing and future updating of this plugin.
105
+ </p>
106
+ <h2>Usage</h2>
107
+ <p>
108
+ In this new version of the Userstamp plug-in, the assumption is that you
109
+ have two different categories of objects; those that mani˝pulate, and
110
+ those that are manipulated. For those objects that are being manipulated
111
+ there&#8216;s the Stampable module and for the manipulators there&#8216;s
112
+ the Stamper module. There&#8216;s also the actual Userstamp module for your
113
+ controllers that assists in setting up your environment on a per request
114
+ basis.
115
+ </p>
116
+ <p>
117
+ To better understand how all this works, I think an example is in order.
118
+ For this example we will assume that a weblog application is comprised of
119
+ User and Post objects. The first thing we need to do is create the
120
+ migrations for these objects, and the plug-in gives you a
121
+ <tt>userstamps</tt> method for very easily doing this:
122
+ </p>
123
+ <pre>
124
+ class CreateUsers &lt; ActiveRecord::Migration
125
+ def self.up
126
+ create_table :users, :force =&gt; true do |t|
127
+ t.timestamps
128
+ t.userstamps
129
+ t.name
130
+ end
131
+ end
132
+
133
+ def self.down
134
+ drop_table :users
135
+ end
136
+ end
137
+
138
+ class CreatePosts &lt; ActiveRecord::Migration
139
+ def self.up
140
+ create_table :posts, :force =&gt; true do |t|
141
+ t.timestamps
142
+ t.userstamps
143
+ t.title
144
+ end
145
+ end
146
+
147
+ def self.down
148
+ drop_table :posts
149
+ end
150
+ end
151
+ </pre>
152
+ <p>
153
+ Second, since Users are going to manipulate other objects in our project,
154
+ we&#8216;ll use the <tt>model_stamper</tt> method in our User class:
155
+ </p>
156
+ <pre>
157
+ class User &lt; ActiveRecord::Base
158
+ model_stamper
159
+ end
160
+ </pre>
161
+ <p>
162
+ Finally, we need to setup a controller to set the current user of the
163
+ application. It&#8216;s recommended that you do this in your
164
+ ApplicationController:
165
+ </p>
166
+ <pre>
167
+ class ApplicationController &lt; ActionController::Base
168
+ include Userstamp
169
+ end
170
+ </pre>
171
+ <p>
172
+ If all you are interested in is making sure all tables that have the proper
173
+ columns are stamped by the currently logged in user you can stop right
174
+ here. More than likely you want all your associations setup on your stamped
175
+ objects, and that&#8216;s where the <tt>stampable</tt> class method comes
176
+ in. So in our example we&#8216;ll want to use this method in both our User
177
+ and Post classes:
178
+ </p>
179
+ <pre>
180
+ class User &lt; ActiveRecord::Base
181
+ model_stamper
182
+ stampable
183
+ end
184
+
185
+ class Post &lt; ActiveRecord::Base
186
+ stampable
187
+ end
188
+ </pre>
189
+ <p>
190
+ Okay, so what all have we done? The <tt>model_stamper</tt> class method
191
+ injects two methods into the User class. They are stamper= and stamper and
192
+ look like this:
193
+ </p>
194
+ <pre>
195
+ def stamper=(object)
196
+ object_stamper = if object.is_a?(ActiveRecord::Base)
197
+ object.send(&quot;#{object.class.primary_key}&quot;.to_sym)
198
+ else
199
+ object
200
+ end
201
+
202
+ Thread.current[&quot;#{self.to_s.downcase}_#{self.object_id}_stamper&quot;] = object_stamper
203
+ end
204
+
205
+ def stamper
206
+ Thread.current[&quot;#{self.to_s.downcase}_#{self.object_id}_stamper&quot;]
207
+ end
208
+ </pre>
209
+ <p>
210
+ The big change with this new version is that we are now using
211
+ Thread.current to save the current stamper so as to avoid conflict with
212
+ concurrent requests.
213
+ </p>
214
+ <p>
215
+ The <tt>stampable</tt> method allows you to customize what columns will get
216
+ stamped, and also creates the <tt>creator</tt>, <tt>updater</tt>, and
217
+ <tt>deleter</tt> associations.
218
+ </p>
219
+ <p>
220
+ The Userstamp module that we included into our ApplicationController uses
221
+ the setter method to set which user is currently making the request. By
222
+ default the &#8216;set_stampers&#8217; method works perfectly with the <a
223
+ href="http://svn.techno-weenie.net/projects/plugins/restful_authentication">RestfulAuthentication</a>
224
+ plug-in:
225
+ </p>
226
+ <pre>
227
+ def set_stampers
228
+ User.stamper = self.current_user
229
+ end
230
+ </pre>
231
+ <p>
232
+ If you aren&#8216;t using ActsAsAuthenticated, then you need to create your
233
+ own version of the <tt>set_stampers</tt> method in the controller where
234
+ you&#8216;ve included the Userstamp module.
235
+ </p>
236
+ <p>
237
+ Now, let&#8216;s get back to the Stampable module (since it really is the
238
+ interesting one). The Stampable module sets up before_* filters that are
239
+ responsible for setting those attributes at the appropriate times. It also
240
+ creates the belongs_to relationships for you.
241
+ </p>
242
+ <p>
243
+ If you need to customize the columns that are stamped, the
244
+ <tt>stampable</tt> method can be completely customized. Here&#8216;s an
245
+ quick example:
246
+ </p>
247
+ <pre>
248
+ class Post &lt; ActiveRecord::Base
249
+ acts_as_stampable :stamper_class_name =&gt; :person,
250
+ :creator_attribute =&gt; :create_user,
251
+ :updater_attribute =&gt; :update_user,
252
+ :deleter_attribute =&gt; :delete_user
253
+ end
254
+ </pre>
255
+ <p>
256
+ If you are upgrading your application from the old version of Userstamp,
257
+ there is a compatibility mode to have the plug-in use the old
258
+ &quot;_by&quot; columns by default. To enable this mode, add the following
259
+ line to the RAILS_ROOT/config/environment.rb file:
260
+ </p>
261
+ <pre>
262
+ Ddb::Userstamp.compatibility_mode = true
263
+ </pre>
264
+ <p>
265
+ If you are having a difficult time getting the Userstamp plug-in to work, I
266
+ recommend you checkout the sample application that I created. You can find
267
+ this application on <a
268
+ href="http://github.com/delynn/userstamp_sample">GitHub</a>
269
+ </p>
270
+ <h2>Uninstall</h2>
271
+ <p>
272
+ Uninstalling the plugin can be done using the built in Rails plugin script.
273
+ Issue the following command from the root of your application:
274
+ </p>
275
+ <pre>
276
+ script/plugin remove userstamp
277
+ </pre>
278
+ <h2>Documentation</h2>
279
+ <p>
280
+ RDoc has been run on the plugin directory and is available in the doc
281
+ directory.
282
+ </p>
283
+ <h2>Running Unit Tests</h2>
284
+ <p>
285
+ There are extensive unit tests in the &quot;test&quot; directory of the
286
+ plugin. These test can be run individually by executing the following
287
+ command from the userstamp directory:
288
+ </p>
289
+ <pre>
290
+ ruby test/compatibility_stamping_test.rb
291
+ ruby test/stamping_test.rb
292
+ ruby test/userstamp_controller_test.rb
293
+ </pre>
294
+ <h2>Bugs &amp; Feedback</h2>
295
+ <p>
296
+ Bug reports and feedback are welcome via my delynn+userstamp@gmail.com
297
+ email address. I also encouraged everyone to clone the git repository and
298
+ make modifications&#8212;I&#8216;ll be more than happy to merge any changes
299
+ from other people&#8216;s branches that would be beneficial to the whole
300
+ project.
301
+ </p>
302
+ <h2>Credits and Special Thanks</h2>
303
+ <p>
304
+ The original idea for this plugin came from the Rails Wiki article entitled
305
+ <a
306
+ href="http://wiki.rubyonrails.com/rails/pages/ExtendingActiveRecordExample">Extending
307
+ ActiveRecord</a>.
308
+ </p>
309
+
310
+ </div>
311
+
312
+
313
+ </div>
314
+
315
+
316
+ </div>
317
+
318
+
319
+ <!-- if includes -->
320
+
321
+ <div id="section">
322
+
323
+
324
+
325
+
326
+
327
+
328
+
329
+
330
+ <!-- if method_list -->
331
+
332
+
333
+ </div>
334
+
335
+
336
+ <div id="validator-badges">
337
+ <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
338
+ </div>
339
+
340
+ </body>
341
+ </html>
@@ -0,0 +1,101 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+
6
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
7
+ <head>
8
+ <title>File: migration_helper.rb</title>
9
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10
+ <meta http-equiv="Content-Script-Type" content="text/javascript" />
11
+ <link rel="stylesheet" href="../.././rdoc-style.css" type="text/css" media="screen" />
12
+ <script type="text/javascript">
13
+ // <![CDATA[
14
+
15
+ function popupCode( url ) {
16
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
17
+ }
18
+
19
+ function toggleCode( id ) {
20
+ if ( document.getElementById )
21
+ elem = document.getElementById( id );
22
+ else if ( document.all )
23
+ elem = eval( "document.all." + id );
24
+ else
25
+ return false;
26
+
27
+ elemStyle = elem.style;
28
+
29
+ if ( elemStyle.display != "block" ) {
30
+ elemStyle.display = "block"
31
+ } else {
32
+ elemStyle.display = "none"
33
+ }
34
+
35
+ return true;
36
+ }
37
+
38
+ // Make codeblocks hidden by default
39
+ document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
40
+
41
+ // ]]>
42
+ </script>
43
+
44
+ </head>
45
+ <body>
46
+
47
+
48
+
49
+ <div id="fileHeader">
50
+ <h1>migration_helper.rb</h1>
51
+ <table class="header-table">
52
+ <tr class="top-aligned-row">
53
+ <td><strong>Path:</strong></td>
54
+ <td>lib/migration_helper.rb
55
+ </td>
56
+ </tr>
57
+ <tr class="top-aligned-row">
58
+ <td><strong>Last Update:</strong></td>
59
+ <td>Sat Apr 05 11:37:18 -0600 2008</td>
60
+ </tr>
61
+ </table>
62
+ </div>
63
+ <!-- banner header -->
64
+
65
+ <div id="bodyContent">
66
+
67
+
68
+
69
+ <div id="contextContent">
70
+
71
+
72
+
73
+ </div>
74
+
75
+
76
+ </div>
77
+
78
+
79
+ <!-- if includes -->
80
+
81
+ <div id="section">
82
+
83
+
84
+
85
+
86
+
87
+
88
+
89
+
90
+ <!-- if method_list -->
91
+
92
+
93
+ </div>
94
+
95
+
96
+ <div id="validator-badges">
97
+ <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
98
+ </div>
99
+
100
+ </body>
101
+ </html>