ipp_quickbase_devkit 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.
Files changed (239) hide show
  1. data/LICENSE +87 -0
  2. data/README.rdoc +112 -0
  3. data/doc/QuickBaseClient.rb.htm +1896 -0
  4. data/doc/ReleaseNotes.txt +43 -0
  5. data/doc/qbc.makeCSVFile.qbc +4 -0
  6. data/doc/qbc.makeCSVFile.rb +4 -0
  7. data/doc/quickbase_adapter.rb.htm +399 -0
  8. data/examples/cookbookfiles/QuickBaseAPICookbook.html +2590 -0
  9. data/examples/cookbookfiles/addChangeRemoveUserRole.rb +21 -0
  10. data/examples/cookbookfiles/addOrEditRecord.rb +10 -0
  11. data/examples/cookbookfiles/application_object.rb +55 -0
  12. data/examples/cookbookfiles/applyRubyFormulas.rb +10 -0
  13. data/examples/cookbookfiles/average.rb +27 -0
  14. data/examples/cookbookfiles/backupApplication.rb +8 -0
  15. data/examples/cookbookfiles/cacheSchemas.rb +53 -0
  16. data/examples/cookbookfiles/calculateRunningTotals.rb +11 -0
  17. data/examples/cookbookfiles/copyrecords.rb +73 -0
  18. data/examples/cookbookfiles/count.rb +26 -0
  19. data/examples/cookbookfiles/createRecordNavigatorHTML.rb +42 -0
  20. data/examples/cookbookfiles/createReportDashboard.rb +35 -0
  21. data/examples/cookbookfiles/createTable.rb +12 -0
  22. data/examples/cookbookfiles/deviation.rb +25 -0
  23. data/examples/cookbookfiles/downloadCookbook.rb +97 -0
  24. data/examples/cookbookfiles/downloadFile.rb +10 -0
  25. data/examples/cookbookfiles/downloadFilesToFolder.rb +81 -0
  26. data/examples/cookbookfiles/downloadToTextFile.rb +64 -0
  27. data/examples/cookbookfiles/dumpSchema.rb +11 -0
  28. data/examples/cookbookfiles/duplicateRecord.rb +8 -0
  29. data/examples/cookbookfiles/dynamicMethods.rb +33 -0
  30. data/examples/cookbookfiles/editRecords.rb +15 -0
  31. data/examples/cookbookfiles/findJohnsLast10Records.rb +17 -0
  32. data/examples/cookbookfiles/findRubyRecords.rb +17 -0
  33. data/examples/cookbookfiles/formatCurrency.rb +24 -0
  34. data/examples/cookbookfiles/formatDate.rb +10 -0
  35. data/examples/cookbookfiles/formatDuration.rb +27 -0
  36. data/examples/cookbookfiles/formatPercent.rb +24 -0
  37. data/examples/cookbookfiles/getAllValuesForFields.rb +18 -0
  38. data/examples/cookbookfiles/getAppDTMInfo.rb +29 -0
  39. data/examples/cookbookfiles/getApplicationVariable.rb +5 -0
  40. data/examples/cookbookfiles/getChildTableDBID.rb +11 -0
  41. data/examples/cookbookfiles/getColumnListForReport.rb +6 -0
  42. data/examples/cookbookfiles/getFieldChoices.rb +13 -0
  43. data/examples/cookbookfiles/getFieldIDs.rb +6 -0
  44. data/examples/cookbookfiles/getFieldNames.rb +6 -0
  45. data/examples/cookbookfiles/getLastModTime.rb +8 -0
  46. data/examples/cookbookfiles/getLastRecModTime.rb +8 -0
  47. data/examples/cookbookfiles/getNumRecords.rb +8 -0
  48. data/examples/cookbookfiles/getNumTables.rb +4 -0
  49. data/examples/cookbookfiles/getRecord.rb +5 -0
  50. data/examples/cookbookfiles/getRecordDisplayURL.rb +13 -0
  51. data/examples/cookbookfiles/getRecordsAddedToday.rb +20 -0
  52. data/examples/cookbookfiles/getRecordsAsJSON.rb +6 -0
  53. data/examples/cookbookfiles/getReportNames.rb +25 -0
  54. data/examples/cookbookfiles/getRoleInfo.rb +48 -0
  55. data/examples/cookbookfiles/getServerStatus.rb +11 -0
  56. data/examples/cookbookfiles/getSortListForReport.rb +6 -0
  57. data/examples/cookbookfiles/getTableIDs.rb +6 -0
  58. data/examples/cookbookfiles/getTableName.rb +8 -0
  59. data/examples/cookbookfiles/getTableNames.rb +25 -0
  60. data/examples/cookbookfiles/getTimeCreated.rb +8 -0
  61. data/examples/cookbookfiles/getTimeInMilliseconds.rb +5 -0
  62. data/examples/cookbookfiles/getUserInfo.rb +26 -0
  63. data/examples/cookbookfiles/getUserRole.rb +15 -0
  64. data/examples/cookbookfiles/intranet.rb +101 -0
  65. data/examples/cookbookfiles/isAverageField.rb +17 -0
  66. data/examples/cookbookfiles/isDbidString.rb +8 -0
  67. data/examples/cookbookfiles/isTotalField.rb +16 -0
  68. data/examples/cookbookfiles/iterateDBPages.rb +8 -0
  69. data/examples/cookbookfiles/iterateFilteredRecords.rb +12 -0
  70. data/examples/cookbookfiles/iterateJoinRecords.rb +68 -0
  71. data/examples/cookbookfiles/iterateRecordInfos.rb +8 -0
  72. data/examples/cookbookfiles/iterateRecords.rb +23 -0
  73. data/examples/cookbookfiles/iterateSummaryRecords.rb +13 -0
  74. data/examples/cookbookfiles/iterateUnionRecords.rb +38 -0
  75. data/examples/cookbookfiles/listAccessibleApplications.rb +6 -0
  76. data/examples/cookbookfiles/logRequestAndResponseXML.rb +8 -0
  77. data/examples/cookbookfiles/lookupFieldPropertyByName.rb +62 -0
  78. data/examples/cookbookfiles/lookupFieldTypeByName.rb +10 -0
  79. data/examples/cookbookfiles/makeCSVFile.rb +4 -0
  80. data/examples/cookbookfiles/makeSlideShow.rb +42 -0
  81. data/examples/cookbookfiles/makerecs.rb +64 -0
  82. data/examples/cookbookfiles/max.rb +26 -0
  83. data/examples/cookbookfiles/min.rb +26 -0
  84. data/examples/cookbookfiles/percent.rb +29 -0
  85. data/examples/cookbookfiles/printChildElements.rb +54 -0
  86. data/examples/cookbookfiles/printNewRecords.rb +12 -0
  87. data/examples/cookbookfiles/processRESTRequest.rb +21 -0
  88. data/examples/cookbookfiles/provisionAndInviteNewUser.rb +13 -0
  89. data/examples/cookbookfiles/purgeRecords.rb +15 -0
  90. data/examples/cookbookfiles/quickbase_adapter.rb.htm +397 -0
  91. data/examples/cookbookfiles/quickbase_record_finder.zip +0 -0
  92. data/examples/cookbookfiles/recordAndFieldIterator.rb +24 -0
  93. data/examples/cookbookfiles/runImport.rb +9 -0
  94. data/examples/cookbookfiles/runQuickBaseTwitterConnector.rb +41 -0
  95. data/examples/cookbookfiles/sendToQuickBase.rb +33 -0
  96. data/examples/cookbookfiles/setDBvar.rb +6 -0
  97. data/examples/cookbookfiles/showRequestAndResponseXML.rb +8 -0
  98. data/examples/cookbookfiles/sqlQuery.rb +11 -0
  99. data/examples/cookbookfiles/stopOnError.rb +10 -0
  100. data/examples/cookbookfiles/sum.rb +26 -0
  101. data/examples/cookbookfiles/twitterFromQuickBase.rb +42 -0
  102. data/examples/cookbookfiles/twitterWithQuickBase.rb +36 -0
  103. data/examples/cookbookfiles/uploadCSVData.rb +20 -0
  104. data/examples/cookbookfiles/uploadExcelData.rb +22 -0
  105. data/examples/cookbookfiles/uploadFileEveryHour.rb +18 -0
  106. data/examples/cookbookfiles/uploadFileIntoNewRecord.rb +8 -0
  107. data/examples/cookbookfiles/uploadFilesFromFolder.exe +0 -0
  108. data/examples/cookbookfiles/uploadFilesFromFolder.rb +69 -0
  109. data/examples/cookbookfiles/useCompanyURL.rb +12 -0
  110. data/examples/cookbookfiles/userRoles.rb +49 -0
  111. data/examples/cookbookfiles/watchCommunityForum.rb +5 -0
  112. data/examples/cookbookfiles/wikifyTable.rb +29 -0
  113. data/examples/cookbookfiles/xmlShortcuts.rb +33 -0
  114. data/examples/pmp/app/controllers/application.rb +7 -0
  115. data/examples/pmp/app/controllers/contacts_controller.rb +8 -0
  116. data/examples/pmp/app/controllers/document_library_controller.rb +2 -0
  117. data/examples/pmp/app/controllers/issues_controller.rb +5 -0
  118. data/examples/pmp/app/controllers/projects_controller.rb +22 -0
  119. data/examples/pmp/app/controllers/resources_controller.rb +2 -0
  120. data/examples/pmp/app/controllers/tasks_controller.rb +13 -0
  121. data/examples/pmp/app/controllers/time_cards_controller.rb +5 -0
  122. data/examples/pmp/app/helpers/application_helper.rb +3 -0
  123. data/examples/pmp/app/helpers/contacts_helper.rb +2 -0
  124. data/examples/pmp/app/helpers/document_library_helper.rb +2 -0
  125. data/examples/pmp/app/helpers/issues_helper.rb +2 -0
  126. data/examples/pmp/app/helpers/projects_helper.rb +2 -0
  127. data/examples/pmp/app/helpers/resources_helper.rb +2 -0
  128. data/examples/pmp/app/helpers/tasks_helper.rb +2 -0
  129. data/examples/pmp/app/helpers/time_cards_helper.rb +2 -0
  130. data/examples/pmp/app/models/contacts.rb +26 -0
  131. data/examples/pmp/app/models/document_library.rb +2 -0
  132. data/examples/pmp/app/models/issues.rb +6 -0
  133. data/examples/pmp/app/models/projects.rb +26 -0
  134. data/examples/pmp/app/models/resources.rb +2 -0
  135. data/examples/pmp/app/models/tasks.rb +12 -0
  136. data/examples/pmp/app/models/time_cards.rb +7 -0
  137. data/examples/pmp/app/schemas/contacts.xml +1 -0
  138. data/examples/pmp/app/schemas/document_library.xml +1 -0
  139. data/examples/pmp/app/schemas/issues.xml +1 -0
  140. data/examples/pmp/app/schemas/pmp.xml +1 -0
  141. data/examples/pmp/app/schemas/projects.xml +1 -0
  142. data/examples/pmp/app/schemas/readme.txt +8 -0
  143. data/examples/pmp/app/schemas/resources.xml +1 -0
  144. data/examples/pmp/app/schemas/tasks.xml +1 -0
  145. data/examples/pmp/app/schemas/time_cards.xml +1 -0
  146. data/examples/pmp/app/views/contacts/companies.rhtml +31 -0
  147. data/examples/pmp/app/views/contacts/project_contacts.rhtml +31 -0
  148. data/examples/pmp/app/views/issues/filter_issues.rhtml +26 -0
  149. data/examples/pmp/app/views/layouts/application.rhtml +56 -0
  150. data/examples/pmp/app/views/projects/all_projects.rhtml +33 -0
  151. data/examples/pmp/app/views/projects/home.rhtml +11 -0
  152. data/examples/pmp/app/views/projects/my_open_projects.rhtml +27 -0
  153. data/examples/pmp/app/views/projects/open_projects.rhtml +44 -0
  154. data/examples/pmp/app/views/projects/project_sorted_by_company.rhtml +40 -0
  155. data/examples/pmp/app/views/projects/projects_sorted_by_priority.rhtml +30 -0
  156. data/examples/pmp/app/views/projects/updated_projects.rhtml +0 -0
  157. data/examples/pmp/app/views/tasks/all_tasks.rhtml +27 -0
  158. data/examples/pmp/app/views/tasks/search.rhtml +23 -0
  159. data/examples/pmp/app/views/tasks/search2.rhtml +23 -0
  160. data/examples/pmp/app/views/tasks/search3.rhtml +23 -0
  161. data/examples/pmp/app/views/time_cards/summary.rhtml +38 -0
  162. data/examples/pmp/config/boot.rb +45 -0
  163. data/examples/pmp/config/database.yml +30 -0
  164. data/examples/pmp/config/environment.rb +60 -0
  165. data/examples/pmp/config/environments/development.rb +21 -0
  166. data/examples/pmp/config/environments/production.rb +18 -0
  167. data/examples/pmp/config/environments/test.rb +19 -0
  168. data/examples/pmp/config/routes.rb +23 -0
  169. data/examples/pmp/db/migrate/001_create_projects.rb +10 -0
  170. data/examples/pmp/db/migrate/002_create_tasks.rb +10 -0
  171. data/examples/pmp/db/migrate/003_create_issues.rb +10 -0
  172. data/examples/pmp/db/migrate/004_create_document_libraries.rb +10 -0
  173. data/examples/pmp/db/migrate/005_create_resources.rb +10 -0
  174. data/examples/pmp/db/migrate/006_create_time_cards.rb +10 -0
  175. data/examples/pmp/db/migrate/007_create_contacts.rb +10 -0
  176. data/examples/pmp/public/404.html +30 -0
  177. data/examples/pmp/public/500.html +30 -0
  178. data/examples/pmp/public/app.index.html +277 -0
  179. data/examples/pmp/public/dispatch.cgi +10 -0
  180. data/examples/pmp/public/dispatch.fcgi +24 -0
  181. data/examples/pmp/public/dispatch.rb +10 -0
  182. data/examples/pmp/public/favicon.ico +0 -0
  183. data/examples/pmp/public/images/rails.png +0 -0
  184. data/examples/pmp/public/javascripts/application.js +2 -0
  185. data/examples/pmp/public/javascripts/controls.js +833 -0
  186. data/examples/pmp/public/javascripts/dragdrop.js +942 -0
  187. data/examples/pmp/public/javascripts/effects.js +1088 -0
  188. data/examples/pmp/public/javascripts/prototype.js +2515 -0
  189. data/examples/pmp/public/robots.txt +1 -0
  190. data/examples/pmp/test/fixtures/contacts.yml +5 -0
  191. data/examples/pmp/test/fixtures/document_libraries.yml +5 -0
  192. data/examples/pmp/test/fixtures/issues.yml +5 -0
  193. data/examples/pmp/test/fixtures/projects.yml +5 -0
  194. data/examples/pmp/test/fixtures/resources.yml +5 -0
  195. data/examples/pmp/test/fixtures/tasks.yml +5 -0
  196. data/examples/pmp/test/fixtures/time_cards.yml +5 -0
  197. data/examples/pmp/test/functional/contacts_controller_test.rb +18 -0
  198. data/examples/pmp/test/functional/document_library_controller_test.rb +18 -0
  199. data/examples/pmp/test/functional/issues_controller_test.rb +18 -0
  200. data/examples/pmp/test/functional/projects_controller_test.rb +18 -0
  201. data/examples/pmp/test/functional/resources_controller_test.rb +18 -0
  202. data/examples/pmp/test/functional/tasks_controller_test.rb +18 -0
  203. data/examples/pmp/test/functional/time_cards_controller_test.rb +18 -0
  204. data/examples/pmp/test/test_helper.rb +28 -0
  205. data/examples/pmp/test/unit/contacts_test.rb +10 -0
  206. data/examples/pmp/test/unit/document_library_test.rb +10 -0
  207. data/examples/pmp/test/unit/issues_test.rb +10 -0
  208. data/examples/pmp/test/unit/projects_test.rb +10 -0
  209. data/examples/pmp/test/unit/resources_test.rb +10 -0
  210. data/examples/pmp/test/unit/tasks_test.rb +10 -0
  211. data/examples/pmp/test/unit/time_cards_test.rb +10 -0
  212. data/lib/QuickBaseClient.rb +5054 -0
  213. data/lib/QuickBaseCommandLineClient.rb +401 -0
  214. data/lib/QuickBaseContactsAppBuilder.rb +419 -0
  215. data/lib/QuickBaseEmailer.rb +334 -0
  216. data/lib/QuickBaseEventNotifier.rb +592 -0
  217. data/lib/QuickBaseMisc.rb +96 -0
  218. data/lib/QuickBaseObjects.rb +566 -0
  219. data/lib/QuickBaseRSSGenerator.rb +286 -0
  220. data/lib/QuickBaseTextData.rb +545 -0
  221. data/lib/QuickBaseTwitterConnector.rb +300 -0
  222. data/lib/QuickBaseWebClient.rb +126 -0
  223. data/lib/WorkPlaceClient.rb +45 -0
  224. data/lib/qbc.makeCSVFile.qbc +4 -0
  225. data/lib/qbc.makeCSVFile.rb +17 -0
  226. data/lib/quickbase_adapter.rb +320 -0
  227. data/lib/runFieldEntryDialog.rb +151 -0
  228. data/lib/runOfflineFieldEntryDialog.rb +203 -0
  229. data/rakefile +100 -0
  230. data/test/run_tests.bat +7 -0
  231. data/test/spec_all_tests.rb +13 -0
  232. data/test/spec_smoke_tests.rb +58 -0
  233. data/test/spec_workplace_addrecord_test.rb +46 -0
  234. data/test/spec_workplace_base_test.rb +57 -0
  235. data/test/spec_workplace_editrecord_test.rb +38 -0
  236. data/test/spec_workplace_json_test.rb +38 -0
  237. data/test/spec_workplace_objects_test.rb +39 -0
  238. data/test/spec_workplace_smoke_tests.rb +45 -0
  239. metadata +353 -0
@@ -0,0 +1,29 @@
1
+
2
+ require 'QuickBaseClient'
3
+
4
+ qbc = QuickBase::Client.new("username","password")
5
+
6
+ qbc.applyPercentToRecords("bcc9qcnxw","number","percent")
7
+
8
+ numberTotal = qbc.sum("bcc9qcnxw",["number"])
9
+ puts "number total: #{numberTotal['number']}"
10
+
11
+ qbc.iterateRecords("bcc9qcnxw",["number","percent"]){|record|
12
+ puts "number: #{record['number']}, percent: #{record['percent'].to_f*100}"
13
+ }
14
+
15
+ percentTotal = qbc.sum("bcc9qcnxw",["percent"])
16
+ puts "percent total: #{percentTotal['percent'].to_f*100}"
17
+
18
+ =begin
19
+
20
+ Sample output of above script:-
21
+
22
+ number total: 124.0
23
+ number: 20, percent: 16.12903225806
24
+ number: 36, percent: 29.03225806452
25
+ number: 56, percent: 45.16129032258
26
+ number: 12, percent: 9.67741935484
27
+ percent total: 100.0
28
+
29
+ =end
@@ -0,0 +1,54 @@
1
+
2
+ require 'QuickBaseClient'
3
+
4
+ qbc = QuickBase::Client.new("username","password")
5
+
6
+ qbc.getSchema(qbc.findDBByname("Application Library"))
7
+
8
+ qbc.printChildElements(qbc.qdbapi)
9
+
10
+ =begin
11
+
12
+ :
13
+ qdbapi :
14
+ action = API_getSchema
15
+ errcode = 0
16
+ errtext = No error
17
+ table :
18
+ name = Application Library
19
+ desc = This QuickBase contains user and QuickBase created applications that can be used by any customer of QuickBase.
20
+ original :
21
+ table_id = bbtt9cjr6
22
+ cre_date = 1152727983612
23
+ mod_date = 1171485722502
24
+ next_record_id = 1
25
+ next_field_id = 12
26
+ next_query_id = 5
27
+ def_sort_fid = 6
28
+ def_sort_order = 0
29
+ chdbids :
30
+ chdbid (name=_dbid_applications ) = bbtt9cjr7
31
+ chdbid (name=_dbid_versions ) = bbtt9cjr8
32
+ chdbid (name=_dbid_documents ) = bbtt9cjr9
33
+ chdbid (name=_dbid_reviews ) = bbtt9cjsc
34
+ chdbid (name=_dbid_installs_requests ) = bbvw9jb72
35
+ chdbid (name=_dbid_feedback ) = bbt4qb5gr
36
+ chdbid (name=_dbid_featured_apps ) = bbt9vg4u5
37
+ chdbid (name=_dbid_categories ) = bbtt9cjsg
38
+ lastluserid = 0
39
+ queries :
40
+ query (id=1 ):
41
+ qyname = List All
42
+ qytype = table
43
+ qycrit = {0.CT.''}
44
+ qycalst = 0.0
45
+ query (id=2 ):
46
+ qyname = List Changes
47
+ qytype = table
48
+ qydesc = Sorted by Date Modified
49
+ qycrit = {0.CT.''}
50
+ qyopts = so-D.onlynew.
51
+ qycalst = 0.0
52
+ fields =
53
+
54
+ =end
@@ -0,0 +1,12 @@
1
+ require 'QuickBaseEventNotifier'
2
+
3
+ # check the QuickBase Community Forum every minute for new or modified records
4
+ QuickBase::EventNotifier.watchAndRunCode("username","password","8emtadvk") {|eventNotification|
5
+ # run this code when a record is added or modified
6
+ qbc = QuickBase::Client.new("username","password")
7
+ fiveMinutesAgo = Time.now - (60*5)
8
+ qbc.doQuery("8emtadvk", "{'2'.GT.'#{fiveMinutesAgo.to_i}'}"){ |record|
9
+ # print records added less than 5 minutes ago
10
+ qbc.printChildElements(record)
11
+ }
12
+ }
@@ -0,0 +1,21 @@
1
+ require 'QuickBaseClient'
2
+
3
+ qbc = QuickBase::Client.new(ENV["quickbase_username"],ENV["quickbase_password"])
4
+
5
+ puts "\nTable id for QuickBase Community Forum:\n\n"
6
+ puts qbc.processRESTRequest("QuickBase Community Forum")
7
+
8
+ puts "\nName of Community Forum table:\n\n"
9
+ puts qbc.processRESTRequest("8emtadvk")
10
+
11
+ puts "\nCommunity Forum record for Ruby wrapper:\n\n"
12
+ puts qbc.processRESTRequest("8emtadvk/24105")
13
+
14
+ puts "\nFunction Names listed in QuickBase Support Center:\n\n"
15
+ puts qbc.processRESTRequest("6ewwzuuj/Function Name")
16
+
17
+ puts "\nRecipe 93 from the QuickBase API Cookbook:\n\n"
18
+ puts qbc.processRESTRequest("QuickBase API Cookbook v3/Recipes/93")
19
+
20
+ puts "\nGet the title of Recipe 93 from the QuickBase API Cookbook:\n\n"
21
+ puts qbc.processRESTRequest("QuickBase API Cookbook v3/Recipes/93/Title")
@@ -0,0 +1,13 @@
1
+
2
+ require 'QuickBaseClient'
3
+
4
+ # Add a new user to QuickBase and email the user an invitation to an application
5
+
6
+ qbc = QuickBase::Client.new("username","password","My Fantastic Application")
7
+
8
+ # Assume "11" is the id of the Participant role in "My Fantastic Application"
9
+
10
+ qbc._provisionUser("11", "fred_flintstone@internet.com", "fred", "flintstone")
11
+
12
+ qbc._sendInvitation(qbc.userid)
13
+
@@ -0,0 +1,15 @@
1
+ require 'QuickBaseClient'
2
+
3
+ #loop {
4
+
5
+ qbc = QuickBase::Client.new( "my_username", "my_password", "my_application" )
6
+ qbc.lookupChdbid( "my_table" )
7
+ qbc._purgeRecords
8
+ qbc.signOut
9
+
10
+ # qbc = nil
11
+ # sleep(60*60)
12
+ #}
13
+
14
+ # to empty a table automatically every hour, remove
15
+ # the '#' from the beginning of the lines above
@@ -0,0 +1,397 @@
1
+ <html>
2
+ <head>
3
+ <title>
4
+ QuickBase Adapter for Ruby on Rails
5
+ </title>
6
+ </head>
7
+ <body>
8
+
9
+ <h2>Overview</h2>
10
+ The QuickBase Adapter for Ruby on Rails is primarily intended for use by developers who are probably already using
11
+ QuickBase, but who need to present QuickBase data in ways that aren't supported by the native QuickBase UI and need
12
+ to process the data in ways that aren't possible via the QuickBase UI. Developers have been able to do this using the HTML
13
+ generated from the QuickBase API, combining it with JavaScript, simple HTML forms, using the SDK's provided by QuickBase, etc.
14
+ However, being able to connect Rails to QuickBase, even in a limited fashion, opens up more options for QuickBase developers to
15
+ present and process QuickBase data in simple and powerful ways.
16
+
17
+ <hr>
18
+
19
+ <h2>Setting up</h2>
20
+ <h3>Get the Ruby wrapper for the QuickBase API</h3>
21
+ You probably already have this because you are reading this file.
22
+ The official home is <a href="https://www.quickbase.com/db/8emtadvk?a=dr&r=ztj&rl=cjtm">here</a>.
23
+ Just download the QuickBaseClient.rb.zip file attached to that QuickBase record, and unzip it into
24
+ its own folder, eg. c:\quickbase\ruby.
25
+
26
+ <h3>Install Ruby on Rails.</h3>
27
+ If you develop on Windows, Instant Rails works great.
28
+ It's very fast to install and to get up and running.
29
+ It's available <a href="http://instantrails.rubyforge.org/wiki/wiki.pl">here</a>.
30
+ <p>
31
+ You can also get all the Rails components by following the instructions from <a href="http://www.rubyonrails.org/down">http://www.rubyonrails.org/down</a>.
32
+
33
+ <h3>Learn the basics of Rails, if necessary</h3>
34
+ If you're new to Rails, go through the exercises at the beginning of the excellent <a href="http://www.pragmaticprogrammer.com/title/rails/">'Agile Development with Rails'</a> book.
35
+ The Rails homepage is <a href="http://www.rubyonrails.org/">http://www.rubyonrails.org/</a>.
36
+
37
+ <h3>Put the quickbase_adapter.rb file in the right place.</h3>
38
+ After installing Rails, search for the file <i>mysql_adapter.rb</i> on your machine. It will be in the connection_adapters folder.
39
+ Copy the quickbase_adapter.rb file into the <i>connection_adapters</i> folder.
40
+
41
+ <h3>Adjust your RUBYLIB environment variable, or edit quickbase_adapter.rb.</h3>
42
+ The quickbase_adapter.rb file depends on the QuickBaseClient.rb file which you extracted from QuickBaseClient.rb.zip.
43
+ Ruby will find the QuickBaseClient.rb file if you set a RUBYLIB environment variable on your machine to include the path to the
44
+ QuickBaseClient.rb file (e.g. <i>c:\quickbase\ruby</i>). Alternatively, you can edit the quickbase_adapter.rb file and change
45
+ the <i>require 'QuickBaseClient'</i> line to include the path to the QuickBaseClient.rb file (e.g. <i>require '\quickbase\ruby\QuickBaseClient'</i>).
46
+
47
+ <h3>Make Rails aware of the QuickBase adapter</h3>
48
+ Search for the active_record.rb file in your Rails installation.
49
+ Inside the file, search for the line starting with '<i>RAILS_CONNECTION_ADAPTERS =%w(...)</i>'.
50
+ Just before the closing ')', add <i> quickbase </i> to the list of adapters.
51
+
52
+ <hr>
53
+
54
+ <h2>Limitations</h2>
55
+ QuickBase does not have an SQL API, and the API it does have can't be translated to the point where Rails
56
+ developers can pretend they are dealing with an SQL database. In particular, the QuickBase API doesn't (yet) allow you
57
+ to add a table to an application; you can create a database (i.e. an 'application') with one table via the API, but you can't
58
+ add more tables to that database via the API.
59
+
60
+ <h3>Can't create tables via SQL</h3>
61
+ The adapter will not process SQL CREATE statements. However, you can use the underlying QuickBase Ruby API to
62
+ create a QuickBase 'Single Table' Application and add fields and data to it.
63
+
64
+ <h3>Doesn't support migrations.</h3>
65
+ Rails migrations involve creating and dropping tables and/or columns.
66
+ Since the adapter doesn't support creating tables using SQL, migrations aren't supported.
67
+ Also, as part of migrations, Rails expects to be able to retrieve and modify database structures by reading schema
68
+ information from the database. While this may be possible at some future date, this first release of the QuickBase adapter
69
+ does not attempt to translate Rails' schema manipulation into QuickBase API calls.
70
+
71
+ <h3>Very limited SQL SELECT support.</h3>
72
+ SELECT statements generated from Rails are translated by the QuickBase API into QuickBase's 'native' query language.
73
+ The QuickBase query language doesn't support the equivalents of JOIN, UNION, MIN, MAX, AVERAGE, COUNT, and many
74
+ other such SELECT clauses and functions. However, you can overcome these limitations using QuickBase
75
+ queries instead of SQL SELECT statements, and by setting up relationships between tables in QuickBase.
76
+
77
+ <h3>Not as fast as other databases</h3>
78
+ QuickBase is not on your server and Rails has to communicate with it by sending and receiving XML over the internet.
79
+ This isn't going to be as fast as using one of the standard SQL databases installed on the same server as Rails or within
80
+ your firewall.
81
+
82
+ <h3>Difficult to switch to another database or from another database</h3>
83
+ QuickBase is not an SQL database and the adapter doesn't support migrations.
84
+ This makes it very difficult to swap out QuickBase from your application and replace it with MySQL or
85
+ any other database. The adapter is really intended for people who are already getting
86
+ a lot of value from QuickBase itself and want to extend that value by connecting QuickBase to the Rails
87
+ framework.
88
+ <p>
89
+ If you want to switch from an SQL database to QuickBase, the QuickBase Ruby API can help copy
90
+ the data across, but wait until you've finished that job before creating your Rails application.
91
+
92
+ <hr>
93
+
94
+ <h2>Recommendations</h2>
95
+
96
+ <h3>Take full advantage of the things that are easy to do in QuickBase</h3>
97
+ QuickBase is great because of how easy it is to create tables, fields, reports, email notifications, etc.
98
+ Don't spend time doing work in Rails that is even easier to do in QuickBase.
99
+
100
+ <h3>Retrieve data using QuickBase queries instead of SQL</h3>
101
+ This will avoid all possible problems with SQL SELECT statements generated by Rails.
102
+ Queries will also run faster.
103
+ (See same subject in 'Goodies' section below.)
104
+
105
+ <h3>Define table relationships in QuickBase rather than in Rails</h3>
106
+ If you need to display and process records composed of fields from multi-tables, start in QuickBase
107
+ by creating relationships between tables, using lookup fields in Reports you define in QuickBase, then
108
+ read the data into Rails by using those Reports. This will be simpler than defining table relationships
109
+ in Rails.
110
+
111
+ <h3>Rails likes models to be singular and tables to be plural</h3>
112
+ If you use Rails scaffolds to get applications up and running quickly, don't forget that the Rails convention is
113
+ for model names to be singular and table names to be plural. e.g. if you have a table of assets, name
114
+ the QuickBase table <i>Assets</i> and name your model <i>Asset</i>. You can turn off this behavior
115
+ in Rails using <i>ActiveRecord::Base.pluralize_table_names = false</i>.
116
+
117
+ <h3>Don't use spaces in your table and field names</h3>
118
+ QuickBase allows this, but SQL doesn't. If you don't actually use any code that generates SQL
119
+ statements, you don't have to worry about this.
120
+
121
+ <h3>Don't change your table or field names after you've written code to access them</h3>
122
+ This recommendation shouldn't be unique to users of the QuickBase adapter; your existing
123
+ code will probably stop working if you do this.
124
+
125
+ <h3>Use unique names for your QuickBase applications and tables</h3>
126
+ Doing this will ensure that you can connect to tables using their names rather than their QuickBase ID's, even
127
+ though it's not a major design flaw to use the ID.
128
+
129
+ <h3>Use lowercase field names</h3>
130
+ If your users won't be viewing anything in QuickBase itself, using lowercase field names will make it easier to
131
+ use default Rails behavior.
132
+
133
+ <hr>
134
+
135
+ <h2>Goodies for QuickBase developers</h2>
136
+
137
+ <h3>Call any QuickBase API method from your model or template code</h3>
138
+ In addition to wrapping all the QuickBase HTTP API calls described in the reference document
139
+ <a href="https://www.quickbase.com/up/6mztyxu8/g/rc7/en/va/QuickBaseAPI.htm">here</a>, the Ruby wrapper for the
140
+ QuickBase API adds a number of helper methods designed reduce the amount of code you have to write
141
+ to retrieve, format, manipulate and update QuickBase data. The Ruby wrapper can be accessed directly
142
+ using <i>ActiveRecord::Base.raw_connection</i>; this will be an instance of the QuickBase::Client class
143
+ from the QuickBaseClient.rb file. Some particularly useful methods are:-
144
+ <ul>
145
+ <li>getAllValuesForFieldsAsArray - get a list of records as an Array of Hashes.
146
+ <li>iterateRecords - loop through the records returned by a QuickBase query. Use
147
+ it in view templates if you can live with bending the MVC paradigm a bit, or accumulate the records
148
+ into an @array in your controller and access that from your view.
149
+ <li>getFilteredRecords - filter records using Ruby regular expressions.
150
+ This can't be done within QuickBase and is very difficult to do with SQL.
151
+ <li>getJoinRecords - get records joined from multiple tables. This makes up for
152
+ not having the SQL version of JOIN.
153
+ <li>getUnionRecords - comparable to an SQL UNION .
154
+ <li>purgeRecords - remove all records from a table.
155
+ <li>setActiveRecord - set the record ID for subsequent record-specific calls, such as setFieldValues.
156
+ <li>setFieldValues - modify the current record using a list of field/value pairs.
157
+ <li>editRecords - modify all the records returned by a query using a list of field/value pairs.
158
+ <li>min,max,count,sum,average - SQL-type functions that are either impossible or difficult to do within
159
+ QuickBase or using the basic QuickBase API.
160
+ <li>applyPercentToRecords, applyDeviationToRecords - compute and set percentage and deviation values across multiple records.
161
+ The QuickBase UI doesn't support 'multi-record' formulas or calculations such as these.
162
+ </ul>
163
+ <p>
164
+ In addition to these and other methods which can be found in the QuickBaseClient.rb file, the Ruby wrapper comes with
165
+ a few other utility classes designed to extend the usefulness of QuickBase beyond its UI. These include an
166
+ RSS generator, for generating RSS from multiple tables, and a QuickBase event notifier that can run ruby code when
167
+ an event occurs in a QuickBase table or record.
168
+ </p>
169
+ In addition to calling these methods using the QuickBase::Client instance returned from <i>ActiveRecord::Base.raw_connection</i>,
170
+ model classes (i.e. classes derived from <i>ActiveRecord</i>) can run methods using the <i>connection.execute</i> method. In 'normal'
171
+ Rails adapters, the <i>execute</i> method is provided so you can send any SQL string directly to your database.
172
+ The equivalent of this in the QuickBase adapter is to give you direct access to methods in the QuickBase::Client class.
173
+ A simple example of this is <i>connection.execute( %q{purgeRecords("jdhfsffee")})</i>, which would remove all records from the
174
+ table with the QuickBase ID of jdhfsffee.
175
+
176
+ <h3>Retrieve data using QuickBase queries instead of SQL</h3>
177
+ If you use Rails' <i>find_by_sql</i> method and send it the name of a Report you've defined in QuickBase, or a query
178
+ expressed in the QuickBase API query language, rather than an actual SQL SELECT statement, the adapter will
179
+ return the data into an array of field/value Hashes as if you had used a SELECT statement.
180
+ An typical example is <i>find_by_sql("List All")</i>. This example will work if your model's class name matches
181
+ your QuickBase table name.
182
+ Note that Rails generates a SELECT statement whenever you use any kind of <i>find</i> method.
183
+ <p>
184
+ You can control which table to query by inserting the table name or QuickBase database ID in front of the
185
+ query, e.g. <i>find_by_sql("Assets:List All")</i>, or <i>find_by_sql("bb737sr8x:List All")</i>.
186
+ The adapater will first look in the current application for the 'Assets' table, then for an application named 'Assets', then
187
+ finally it will attempt to find the table with 'Assets' as the ID. Of course, the second example (bb737sr8x) is more
188
+ likely to succeed when the adapter looks for a QuickBase table ID. This is useful if your model's class name is different
189
+ from the corresponding QuickBase table name.
190
+ <p>
191
+ Thanks to a sneaky trick in the QuickBase adapter, if your model class reads fields from a <i>different</i>
192
+ table from the QuickBase table it is associated with, you can still retrieve field values using Active
193
+ Record's clever <i>record.field</i> syntax.
194
+
195
+ <h3>Use QuickBase field ID's in SQL SELECT statements</h3>
196
+ QuickBase fields all have an ID that doesn't change when you change the field's name.
197
+ When the QuickBase::Client parses an SQL statement, it will understand field ID's if you use them instead of
198
+ field names. It works for both the columns to SELECT and the columns to ORDER BY. You may be able
199
+ to use this to process QuickBase fields with spaces in their names.
200
+ An example would be <i>SELECT 3 FROM Assets</i> - '3' is always the 'Record ID#' field in QuickBase.
201
+
202
+ <h3>Display the QuickBase requests and responses</h3>
203
+ Put <i>printRequestsAndResponses: true</i> in your database.yml to see the XML sent to
204
+ QuickBase and received from QuickBase. This is very useful for debugging. The information
205
+ will be displayed in your Rails 'Console' window.
206
+
207
+ <h3>Cache QuickBase schemas</h3>
208
+ Put <i>cacheSchemas: true</i> in your database.yml if you are <i>sure</i> that the
209
+ schemas of the QuickBase tables used by your Rails application will not change
210
+ while your application is running. This will significantly reduce the number of
211
+ over-the-wire requests the adapter has to make to QuickBase.
212
+
213
+ <h3>Specify the precision of numeric fields in database.yml</h3>
214
+ QuickBase apparently doesn't limit the size of numeric fields.
215
+ To specify the precision of all 'decimal' fields in your application, put (e.g.) <i>decimalPrecision: 32</i>
216
+ in database.yml.
217
+
218
+ <h3>Specifiy the database using the QuickBase ID instead of the application name</h3>
219
+ In your application's database.yml file, you can use a QuickBase DBID instead of a QuickBase
220
+ application name. e.g. <i>database: bbtt9cjr6</i>.
221
+
222
+ <hr>
223
+
224
+ <h2>Sample Rails+QuickBase applications</h2>
225
+
226
+ <b><i>This section is Under Construction ... not ready yet!</i></b>
227
+ <h3>Project Manager Plus</h3>
228
+ This application demontrates various ways of retrieving and displaying data from QuickBase.
229
+ <ol>
230
+ <li>Go the the <a href="https://www.quickbase.com/db/bbtt9cjr6">QuickBase Application Library</a>.
231
+ <li>The Project Manager Plus application is <a href="https://www.quickbase.com/db/bbtt9cjr7?a=dr&rid=40">here</a>.
232
+ <li>Click on the <i>Get App</i> button to copy it to your QuickBase account.
233
+ <li>After you've copied it, be careful not to delete any of the sample data in the tables, and avoid modifying the definition
234
+ of any of the tables and fields. It's OK to add records to any of the tables.
235
+ <li>Unzip the pmp.zip file into your <i>rails_apps</i> folder. You should see the usual set of folders, with several .rb files
236
+ in the ..\pmp\app\controllers, ..\pmp\app\models, ..\pmp\app\views folders.
237
+ <li>In the ..\pmp\config\ folder, open the database.yml file and change the username and password to your
238
+ QuickBase username and password.
239
+ <li>Start Rails with the usual <i>ruby script/server</i> command.
240
+ <li>Point your browser at the appropriate host and port, e.g. <i>http://localhost:3000/</i>, to connect to Rails.
241
+ <li>Click on the links on the left of the screen to see different ways of retrieving records from QuickBase.
242
+ The pages are deliberately uninteresting in appearance in order to simplify the MVC code to focus on reading records.
243
+ </ol>
244
+
245
+ <h3>Contacts database</h3>
246
+ This application demonstrates basic CRUD operations, and how to generate a QuickBase database and a Rails app for it.
247
+
248
+ <ol>
249
+ <li>Put the <i>QuickBaseContactsAppBuilder.rb</i> file in your rails_apps folder.
250
+ <li>From the command line in the rails_apps folder, type <i>ruby QuickBaseContactsAppBuilder.rb username password</i>.
251
+ <i>username</i> and <i>password</i> should be your QuickBase username and password. This should generate a rails
252
+ app named <i>&lt;username&gt;_contacts</i> and an application in QuickBase with the same name. The QuickBase
253
+ application is a single table application.
254
+ <li>From the <i>&lt;username&gt;_contacts</i> folder, run <i>ruby script/server</i>.
255
+ <li>Point your browser at the appropriate host and port, e.g. <i>http://localhost:3000/</i>, to connect to Rails.
256
+ </ol>
257
+
258
+ <hr>
259
+
260
+ <h2>Under the Hood</h2>
261
+
262
+ The Ruby wrapper for the QuickBase API has evolved over 18 months from being a thin wrapper around the
263
+ QuickBase HTTP API to a small library of methods that reduce the work you have to do to get common and
264
+ important things done using QuickBase. Several methods were added to make the QuickBase Rails adapter
265
+ work, so the adapter could remain small and the Ruby wrapper could provide more functionality to anyone
266
+ using it without Rails.
267
+ <p>
268
+ One could argue that the QuickBase API could be used directly from within Rails models, views
269
+ and controllers without going through the adapter. That is certainly true and some applications might work better that way.
270
+ However, the adapter helps developers work more in the 'Rails way' and definitely saves time as you add more Rails applications.
271
+ It's also technically possible to largely bypass Active Record and use the Rails MVC framework by processing lists of records
272
+ from QuickBase as Arrays of Hashes, but you will lose the benefits of Active Record by doing this.
273
+
274
+ <h3>Applications and Tables</h3>
275
+
276
+ As with all the Rails adapters, the QuickBase adapter encapsulates the over-the-wire connection to the database so that
277
+ the database.yml file in your application is the only thing you have to modify to connect to the appropriate QuickBase
278
+ application, e.g. -
279
+
280
+ <pre>
281
+
282
+ development:
283
+ adapter: quickbase
284
+ database: myQuickBaseApplication
285
+ username: myQuickBaseUsername
286
+ password: myQuickBasePassword
287
+
288
+ </pre>
289
+
290
+ This is enough information for the QuickBase adapter to create a QuickBase::Client that connects to your QuickBase
291
+ application using a valid username and password. The QuickBase::Client connection is then accessible in your Rails code
292
+ using <i>ActiveRecord::Base.raw_connection</i>.
293
+
294
+ <p>
295
+ A QuickBase 'application' is a set of one or more tables accessible to a selected group of users via a 'Dashboard' and a menu.
296
+ However, the QuickBase API treats tables as independent things and 'applications' are only visible to the API as a parent table
297
+ with a set of child tables. If your application is a 'Single-table' application, the API sees the application as just a table. With applications
298
+ that start out as a 'Single-table' application then later become 'Multi-table', the name of the application is also the name of
299
+ the 'Single' table you started with. The 'database' line in your database.yml file can be the name of a application or a table. Either way,
300
+ the name of the application or table in your database.yml should be unique for the 'myQuickBaseUsername' user, to help avoid connecting to
301
+ the wrong table or application.
302
+ <p>
303
+ When the QuickBase adapter processes an SQL SELECT statement, it uses the table name in the FROM clause to find the
304
+ correct table in your application, by looking through the list of child tables if necessary. As with all the QuickBase::Client
305
+ methods that access tables, once you have accessed a table, that table is the default for any subsequent QuickBase::Client
306
+ method calls. QuickBase::Client.dbid contains the ID of the last accessed QuickBase table. This saves you having to find
307
+ a table between every API call to do something with the same table.
308
+ <p>
309
+ You can also access tables that aren't in the QuickBase application specified in database.yml if your model name matches
310
+ the name of a different application. You can also access any QuickBase table from any application if you use QuickBase
311
+ queries instead of SQL SELECT statements. This is not possible using the other SQL database Rails adapters . To see exactly
312
+ how the adapter does this, look at the <i>select</i> and <i>setActiveTable</i> methods in quickbase_adapter.rb.
313
+
314
+ <h3>Columns and Fields</h3>
315
+ The QuickBase adapter supports the Rails convention of dynamically reading the list of columns from the active table.
316
+ In QuickBase, 'columns' are referred to as 'fields'. The adapter attempts to accomodate spaces you might be using
317
+ in your QuickBase field names, but spaces in field names might be a problem when you let Rails add or update QuickBase
318
+ records via SQL INSERT and UPDATE statements.
319
+ <p>
320
+ When fields are read from QuickBase and turned into columns for Rails, the adapter makes it's best guess as to the display format that
321
+ should be used for each field, as well as the default value for each field. The adapter assumes that numeric fields will not
322
+ have decimal places unless the number of places is specificied in QuickBase. Look at the <i>columns</i> method in quickbase_adapter.rb
323
+ to see exactly what it does.
324
+ <p>
325
+ Note that if you use <i>cacheSchemas: true</i> in your database.yml, the adapter will retrieve each QuickBase table's
326
+ schema only once, so it's a bad idea to remove or modify fields in those QuickBase tables while Rails is interacting
327
+ with them. Using <i>cacheSchemas: true</i> can knock several seconds off the time it takes to read any amount of
328
+ data from QuickBase.
329
+ <p>
330
+ When you let Rails find records via SQL SELECT (generated by <i>find</i> calls), or by using <i>find_by_sql</i> using
331
+ a QuickBase query, the adapter copies the table's "Record ID#" field to an "id" column so that subsequent UPDATE and DELETE
332
+ calls will know what record to operate on. If you retrieve records directly via the QuickBase::Client in your code, you may
333
+ also have to copy the key field to an "id" column in order to make subsequent UPDATE and DELETE calls to QuickBase
334
+ via the default Rails actions for editing and destroying records.
335
+ <p>
336
+ If your table has a key field that is different from the Record ID#, the adapter makes Rails aware that it is the primary key field.
337
+ However, note that the Record ID# field, or whatever you may have renamed it to, is always used to retrieve and update specific records.
338
+ <p>
339
+ QuickBase tables all have a number of 'built-in' fields, which are read-only. By default ,the QuickBase adapter makes these fields
340
+ unavailable for editing in Rails by renaming those fields to make Rails exclude them from its list of 'content' columns. It
341
+ does this by appending "_id" the those fields' names. The 'built-in' fields are:-
342
+
343
+ <ul>
344
+ <li>Date Created
345
+ <li>Date Modified
346
+ <li>Record Owner
347
+ <li>Last Modified By
348
+ </ul>
349
+
350
+ <p>
351
+ <i>Record ID#</i> is also a 'built-in' QuickBase field but is usually copied to "id", as described above.
352
+ <p>
353
+
354
+ QuickBase lets you change the name of these built-in fields, but the adapter looks at their ID's rather
355
+ than their names. These fields can still be displayed in your views if you access them
356
+ using (e.g.) <i>record["Date Created"]</i>.
357
+
358
+ <h3>Queries</h3>
359
+
360
+ The QuickBase adapter's <i>select</i> method processes all queries.
361
+ <ul>
362
+ <li>
363
+ A query string starting with <i>SELECT</i> is presumed to be an SQL SELECT statement.
364
+ The adapter sends this to the <i>QuickBase::Client.doSQLQuery()</i> method, in QuickBaseClient.rb.
365
+ This method does its best to parse the SQL and translate it into a query expressed in the QuickBase query language.
366
+ The only SQL keywords it can handle are <i>SELECT, count(*), FROM, WHERE, ORDER BY, LIMIT, OFFSET</i>.
367
+ The field names in the SELECT and WHERE clauses can be QuickBase field ID's instead of names, which is useful for
368
+ QuickBase field names that contain spaces.
369
+ <p>
370
+ Any variation of the ActiveRecord <i>find</i> method will result in an SQL SELECT statement.
371
+ For fields that do not contain spaces in their names, you can use ActiveRecord's
372
+ dynamic <i>find_by_??</i> and <i>find_all_by_??</i> methods, e.g. <i>find_all_by_status("Complete")</i>.
373
+ <li>
374
+ A query string starting with <i>{</i> and ending with <i>}</i> is assumed to be a query expressed in the QuickBase
375
+ query language. This is sent 'as is' to QuickBase.
376
+ To understand the QuickBase query language, read the section towards the bottom of <a href="https://www.quickbase.com/up/6mztyxu8/g/rc7/en/va/QuickBaseAPI.htm">QuickBaseAPI.htm</a>.
377
+ <li>
378
+ Any other query string is assumed to be the name of a Report defined in QuickBase.
379
+ If the string contains a colon (':'), any text before the colon will be treated as the name or ID of the QuickBase
380
+ table to query. Look at the adapter's <i>setActiveTable</i> method to understand how the correct QuickBase table
381
+ is located for the query.
382
+
383
+ </ul>
384
+ <p>
385
+ The <i>select</i> method returns an Array of records, each record being a Hash of field/value pairs.
386
+ This is what ActiveRecord expects. ActiveRecord expects each field to have a corresponding column; see the adapter's
387
+ <i>columns</i> method and its QuickBaseColumn class to understand how the adapter provides what ActiveRecord
388
+ expects.
389
+ <p>
390
+ The raw data returned from QuickBase is not formatted as it appears in QuickBase.
391
+ E.g. date, currency and percent field values are unformatted. The QuickBase::Client class formats
392
+ these field values appropriately before returning them, but if you bypass ActiveRecord by accessing
393
+ QuickBase::Client methods directly, or via the adapter's <i>execute</i> method, you must format
394
+ the raw data in your code. Rails has helper methods for formatting data.
395
+
396
+ </body>
397
+ </html>