ccls-ccls_engine 3.11.0

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 (269) hide show
  1. data/README.rdoc +182 -0
  2. data/app/models/abstract.rb +181 -0
  3. data/app/models/abstract_search.rb +50 -0
  4. data/app/models/abstract_validations.rb +324 -0
  5. data/app/models/address.rb +70 -0
  6. data/app/models/address_type.rb +15 -0
  7. data/app/models/addressing.rb +147 -0
  8. data/app/models/aliquot.rb +44 -0
  9. data/app/models/aliquot_sample_format.rb +13 -0
  10. data/app/models/analysis.rb +14 -0
  11. data/app/models/bc_request.rb +20 -0
  12. data/app/models/candidate_control.rb +101 -0
  13. data/app/models/context.rb +23 -0
  14. data/app/models/context_data_source.rb +4 -0
  15. data/app/models/county.rb +16 -0
  16. data/app/models/data_source.rb +24 -0
  17. data/app/models/diagnosis.rb +23 -0
  18. data/app/models/document_type.rb +16 -0
  19. data/app/models/document_version.rb +27 -0
  20. data/app/models/enrollment.rb +78 -0
  21. data/app/models/enrollment_validations.rb +167 -0
  22. data/app/models/follow_up.rb +16 -0
  23. data/app/models/follow_up_type.rb +18 -0
  24. data/app/models/gift_card.rb +22 -0
  25. data/app/models/gift_card_search.rb +137 -0
  26. data/app/models/home_exposure_response.rb +24 -0
  27. data/app/models/homex_outcome.rb +75 -0
  28. data/app/models/hospital.rb +22 -0
  29. data/app/models/icf_master_id.rb +30 -0
  30. data/app/models/icf_master_tracker.rb +217 -0
  31. data/app/models/icf_master_tracker_change.rb +9 -0
  32. data/app/models/icf_master_tracker_update.rb +50 -0
  33. data/app/models/ineligible_reason.rb +26 -0
  34. data/app/models/instrument.rb +26 -0
  35. data/app/models/instrument_type.rb +17 -0
  36. data/app/models/instrument_version.rb +28 -0
  37. data/app/models/interview.rb +122 -0
  38. data/app/models/interview_method.rb +17 -0
  39. data/app/models/interview_outcome.rb +16 -0
  40. data/app/models/language.rb +28 -0
  41. data/app/models/live_birth_data_update.rb +142 -0
  42. data/app/models/operational_event.rb +99 -0
  43. data/app/models/operational_event_type.rb +31 -0
  44. data/app/models/organization.rb +28 -0
  45. data/app/models/patient.rb +63 -0
  46. data/app/models/patient_validations.rb +118 -0
  47. data/app/models/person.rb +28 -0
  48. data/app/models/phone_number.rb +105 -0
  49. data/app/models/phone_type.rb +15 -0
  50. data/app/models/project.rb +39 -0
  51. data/app/models/project_outcome.rb +19 -0
  52. data/app/models/race.rb +31 -0
  53. data/app/models/refusal_reason.rb +23 -0
  54. data/app/models/sample.rb +168 -0
  55. data/app/models/sample_kit.rb +14 -0
  56. data/app/models/sample_outcome.rb +16 -0
  57. data/app/models/sample_temperature.rb +14 -0
  58. data/app/models/sample_type.rb +37 -0
  59. data/app/models/search.rb +195 -0
  60. data/app/models/section.rb +18 -0
  61. data/app/models/state.rb +25 -0
  62. data/app/models/study_subject.rb +237 -0
  63. data/app/models/study_subject_abstracts.rb +47 -0
  64. data/app/models/study_subject_addresses.rb +34 -0
  65. data/app/models/study_subject_associations.rb +38 -0
  66. data/app/models/study_subject_duplicates.rb +111 -0
  67. data/app/models/study_subject_enrollments.rb +17 -0
  68. data/app/models/study_subject_homex_outcome.rb +22 -0
  69. data/app/models/study_subject_identifier.rb +153 -0
  70. data/app/models/study_subject_interviews.rb +25 -0
  71. data/app/models/study_subject_languages.rb +21 -0
  72. data/app/models/study_subject_operational_events.rb +66 -0
  73. data/app/models/study_subject_patient.rb +177 -0
  74. data/app/models/study_subject_pii.rb +74 -0
  75. data/app/models/study_subject_races.rb +25 -0
  76. data/app/models/study_subject_search.rb +260 -0
  77. data/app/models/study_subject_validations.rb +116 -0
  78. data/app/models/subject_language.rb +11 -0
  79. data/app/models/subject_race.rb +11 -0
  80. data/app/models/subject_relationship.rb +21 -0
  81. data/app/models/subject_type.rb +22 -0
  82. data/app/models/tracing_status.rb +20 -0
  83. data/app/models/transfer.rb +40 -0
  84. data/app/models/unit.rb +14 -0
  85. data/app/models/vital_status.rb +19 -0
  86. data/app/models/zip_code.rb +36 -0
  87. data/config/abstract_fields.yml +1038 -0
  88. data/config/abstract_sections.yml +77 -0
  89. data/config/home_exposure_response_fields.yml +583 -0
  90. data/config/icf_master_tracker_update.yml +56 -0
  91. data/config/live_birth_data_update.yml +56 -0
  92. data/config/shared_use_db.yml +4 -0
  93. data/generators/ccls_engine/USAGE +2 -0
  94. data/generators/ccls_engine/ccls_engine_generator.rb +123 -0
  95. data/generators/ccls_engine/templates/autotest_ccls_engine.rb +3 -0
  96. data/generators/ccls_engine/templates/ccls_engine.rake +12 -0
  97. data/generators/ccls_engine/templates/fixtures/address_types.yml +30 -0
  98. data/generators/ccls_engine/templates/fixtures/context_data_sources.yml +54 -0
  99. data/generators/ccls_engine/templates/fixtures/contexts.yml +19 -0
  100. data/generators/ccls_engine/templates/fixtures/data_sources.yml +40 -0
  101. data/generators/ccls_engine/templates/fixtures/diagnoses.yml +40 -0
  102. data/generators/ccls_engine/templates/fixtures/document_types.yml +65 -0
  103. data/generators/ccls_engine/templates/fixtures/document_versions.csv +155 -0
  104. data/generators/ccls_engine/templates/fixtures/follow_up_types.yml +16 -0
  105. data/generators/ccls_engine/templates/fixtures/hospitals.yml +114 -0
  106. data/generators/ccls_engine/templates/fixtures/ineligible_reasons.yml +35 -0
  107. data/generators/ccls_engine/templates/fixtures/instrument_types.yml +26 -0
  108. data/generators/ccls_engine/templates/fixtures/instrument_versions.yml +22 -0
  109. data/generators/ccls_engine/templates/fixtures/instruments.yml +22 -0
  110. data/generators/ccls_engine/templates/fixtures/interview_methods.yml +30 -0
  111. data/generators/ccls_engine/templates/fixtures/interview_outcomes.yml +31 -0
  112. data/generators/ccls_engine/templates/fixtures/languages.yml +34 -0
  113. data/generators/ccls_engine/templates/fixtures/operational_event_types.yml +141 -0
  114. data/generators/ccls_engine/templates/fixtures/organizations.yml +198 -0
  115. data/generators/ccls_engine/templates/fixtures/people.yml +130 -0
  116. data/generators/ccls_engine/templates/fixtures/phone_types.yml +30 -0
  117. data/generators/ccls_engine/templates/fixtures/project_outcomes.yml +25 -0
  118. data/generators/ccls_engine/templates/fixtures/projects.yml +59 -0
  119. data/generators/ccls_engine/templates/fixtures/races.yml +52 -0
  120. data/generators/ccls_engine/templates/fixtures/refusal_reasons.yml +55 -0
  121. data/generators/ccls_engine/templates/fixtures/sample_outcomes.yml +36 -0
  122. data/generators/ccls_engine/templates/fixtures/sample_temperatures.yml +16 -0
  123. data/generators/ccls_engine/templates/fixtures/sample_types.yml +147 -0
  124. data/generators/ccls_engine/templates/fixtures/sections.yml +31 -0
  125. data/generators/ccls_engine/templates/fixtures/states.yml +363 -0
  126. data/generators/ccls_engine/templates/fixtures/subject_relationships.yml +46 -0
  127. data/generators/ccls_engine/templates/fixtures/subject_types.yml +30 -0
  128. data/generators/ccls_engine/templates/fixtures/tracing_statuses.yml +30 -0
  129. data/generators/ccls_engine/templates/fixtures/units.yml +13 -0
  130. data/generators/ccls_engine/templates/fixtures/vital_statuses.yml +28 -0
  131. data/generators/ccls_engine/templates/functional/roles_controller_test.rb +142 -0
  132. data/generators/ccls_engine/templates/functional/sessions_controller_test.rb +19 -0
  133. data/generators/ccls_engine/templates/functional/users_controller_test.rb +94 -0
  134. data/generators/ccls_engine/templates/images/sort_down.png +0 -0
  135. data/generators/ccls_engine/templates/images/sort_up.png +0 -0
  136. data/generators/ccls_engine/templates/initializer.rb +28 -0
  137. data/generators/ccls_engine/templates/javascripts/ccls_engine.js +24 -0
  138. data/generators/ccls_engine/templates/javascripts/jquery-ui.js +763 -0
  139. data/generators/ccls_engine/templates/javascripts/jquery.js +154 -0
  140. data/generators/ccls_engine/templates/javascripts/jrails.js +1 -0
  141. data/generators/ccls_engine/templates/migrations/create_user_invitations.rb +18 -0
  142. data/generators/ccls_engine/templates/migrations/create_users.rb +33 -0
  143. data/generators/ccls_engine/templates/migrations/drop_user_invitations.rb +18 -0
  144. data/generators/ccls_engine/templates/stylesheets/ccls_engine.css +180 -0
  145. data/generators/ccls_engine/templates/stylesheets/user.css +35 -0
  146. data/generators/ccls_engine/templates/stylesheets/users.css +23 -0
  147. data/generators/ccls_engine/templates/unit/core_extension_test.rb +18 -0
  148. data/generators/ccls_engine/templates/unit/role_test.rb +30 -0
  149. data/generators/ccls_engine/templates/unit/user_test.rb +321 -0
  150. data/lib/ccls-ccls_engine.rb +1 -0
  151. data/lib/ccls_engine.rb +135 -0
  152. data/lib/ccls_engine/action_view_extension.rb +3 -0
  153. data/lib/ccls_engine/action_view_extension/base.rb +53 -0
  154. data/lib/ccls_engine/action_view_extension/form_builder.rb +39 -0
  155. data/lib/ccls_engine/active_record_extension.rb +2 -0
  156. data/lib/ccls_engine/active_record_extension/base.rb +70 -0
  157. data/lib/ccls_engine/active_record_shared.rb +8 -0
  158. data/lib/ccls_engine/assertions.rb +69 -0
  159. data/lib/ccls_engine/autotest.rb +54 -0
  160. data/lib/ccls_engine/ccls_user.rb +117 -0
  161. data/lib/ccls_engine/core_extension.rb +14 -0
  162. data/lib/ccls_engine/date_and_time_formats.rb +30 -0
  163. data/lib/ccls_engine/factories.rb +880 -0
  164. data/lib/ccls_engine/factory_test_helper.rb +276 -0
  165. data/lib/ccls_engine/helper.rb +112 -0
  166. data/lib/ccls_engine/icf_master_tracker_update_test_helper.rb +121 -0
  167. data/lib/ccls_engine/live_birth_data_update_test_helper.rb +110 -0
  168. data/lib/ccls_engine/package_test_helper.rb +49 -0
  169. data/lib/ccls_engine/shared_database.rb +20 -0
  170. data/lib/ccls_engine/tasks.rb +1 -0
  171. data/lib/ccls_engine/test_tasks.rb +52 -0
  172. data/lib/ccls_engine/translation_table.rb +86 -0
  173. data/lib/shared_migration.rb +5 -0
  174. data/lib/surveyor/survey_extensions.rb +125 -0
  175. data/lib/tasks/application.rake +286 -0
  176. data/lib/tasks/calnet_authenticated.rake +6 -0
  177. data/lib/tasks/common_lib.rake +7 -0
  178. data/lib/tasks/database.rake +288 -0
  179. data/lib/tasks/documentation.rake +71 -0
  180. data/lib/tasks/homex_import.rake +723 -0
  181. data/lib/tasks/odms_import.rake +1116 -0
  182. data/lib/tasks/simply_authorized.rake +6 -0
  183. data/lib/tasks/ucb_ccls_engine_tasks.rake +4 -0
  184. data/lib/tasks/use_db.rake +4 -0
  185. data/rails/init.rb +4 -0
  186. data/test/unit/ccls/abstract_search_test.rb +150 -0
  187. data/test/unit/ccls/abstract_test.rb +674 -0
  188. data/test/unit/ccls/address_test.rb +155 -0
  189. data/test/unit/ccls/address_type_test.rb +25 -0
  190. data/test/unit/ccls/addressing_test.rb +466 -0
  191. data/test/unit/ccls/aliquot_sample_format_test.rb +20 -0
  192. data/test/unit/ccls/aliquot_test.rb +156 -0
  193. data/test/unit/ccls/analysis_test.rb +31 -0
  194. data/test/unit/ccls/bc_request_test.rb +43 -0
  195. data/test/unit/ccls/candidate_control_test.rb +712 -0
  196. data/test/unit/ccls/context_data_source_test.rb +26 -0
  197. data/test/unit/ccls/context_test.rb +40 -0
  198. data/test/unit/ccls/core_extension_test.rb +17 -0
  199. data/test/unit/ccls/county_test.rb +34 -0
  200. data/test/unit/ccls/data_source_test.rb +41 -0
  201. data/test/unit/ccls/diagnosis_test.rb +51 -0
  202. data/test/unit/ccls/document_type_test.rb +35 -0
  203. data/test/unit/ccls/document_version_test.rb +68 -0
  204. data/test/unit/ccls/enrollment_test.rb +575 -0
  205. data/test/unit/ccls/follow_up_test.rb +23 -0
  206. data/test/unit/ccls/follow_up_type_test.rb +34 -0
  207. data/test/unit/ccls/gift_card_search_test.rb +153 -0
  208. data/test/unit/ccls/gift_card_test.rb +40 -0
  209. data/test/unit/ccls/home_exposure_response_test.rb +83 -0
  210. data/test/unit/ccls/homex_outcome_test.rb +199 -0
  211. data/test/unit/ccls/hospital_test.rb +102 -0
  212. data/test/unit/ccls/icf_master_id_test.rb +30 -0
  213. data/test/unit/ccls/icf_master_tracker_change_test.rb +14 -0
  214. data/test/unit/ccls/icf_master_tracker_test.rb +132 -0
  215. data/test/unit/ccls/icf_master_tracker_update_test.rb +176 -0
  216. data/test/unit/ccls/ineligible_reason_test.rb +48 -0
  217. data/test/unit/ccls/instrument_test.rb +62 -0
  218. data/test/unit/ccls/instrument_type_test.rb +39 -0
  219. data/test/unit/ccls/instrument_version_test.rb +71 -0
  220. data/test/unit/ccls/interview_method_test.rb +44 -0
  221. data/test/unit/ccls/interview_outcome_test.rb +34 -0
  222. data/test/unit/ccls/interview_test.rb +298 -0
  223. data/test/unit/ccls/language_test.rb +47 -0
  224. data/test/unit/ccls/live_birth_data_update_test.rb +358 -0
  225. data/test/unit/ccls/operational_event_test.rb +187 -0
  226. data/test/unit/ccls/operational_event_type_test.rb +51 -0
  227. data/test/unit/ccls/organization_test.rb +64 -0
  228. data/test/unit/ccls/patient_test.rb +538 -0
  229. data/test/unit/ccls/person_test.rb +55 -0
  230. data/test/unit/ccls/phone_number_test.rb +244 -0
  231. data/test/unit/ccls/phone_type_test.rb +32 -0
  232. data/test/unit/ccls/project_outcome_test.rb +34 -0
  233. data/test/unit/ccls/project_test.rb +60 -0
  234. data/test/unit/ccls/race_test.rb +37 -0
  235. data/test/unit/ccls/refusal_reason_test.rb +52 -0
  236. data/test/unit/ccls/role_test.rb +26 -0
  237. data/test/unit/ccls/sample_kit_test.rb +35 -0
  238. data/test/unit/ccls/sample_outcome_test.rb +34 -0
  239. data/test/unit/ccls/sample_temperature_test.rb +25 -0
  240. data/test/unit/ccls/sample_test.rb +363 -0
  241. data/test/unit/ccls/sample_type_test.rb +58 -0
  242. data/test/unit/ccls/section_test.rb +34 -0
  243. data/test/unit/ccls/state_test.rb +31 -0
  244. data/test/unit/ccls/study_subject_abstracts_test.rb +115 -0
  245. data/test/unit/ccls/study_subject_addresses_test.rb +93 -0
  246. data/test/unit/ccls/study_subject_duplicates_test.rb +407 -0
  247. data/test/unit/ccls/study_subject_enrollments_test.rb +65 -0
  248. data/test/unit/ccls/study_subject_homex_outcome_test.rb +64 -0
  249. data/test/unit/ccls/study_subject_identifier_test.rb +439 -0
  250. data/test/unit/ccls/study_subject_interviews_test.rb +26 -0
  251. data/test/unit/ccls/study_subject_languages_test.rb +142 -0
  252. data/test/unit/ccls/study_subject_operational_events_test.rb +53 -0
  253. data/test/unit/ccls/study_subject_patient_test.rb +249 -0
  254. data/test/unit/ccls/study_subject_pii_test.rb +278 -0
  255. data/test/unit/ccls/study_subject_races_test.rb +203 -0
  256. data/test/unit/ccls/study_subject_search_test.rb +704 -0
  257. data/test/unit/ccls/study_subject_test.rb +770 -0
  258. data/test/unit/ccls/subject_language_test.rb +43 -0
  259. data/test/unit/ccls/subject_race_test.rb +35 -0
  260. data/test/unit/ccls/subject_relationship_test.rb +43 -0
  261. data/test/unit/ccls/subject_type_test.rb +40 -0
  262. data/test/unit/ccls/tracing_status_test.rb +32 -0
  263. data/test/unit/ccls/transfer_test.rb +81 -0
  264. data/test/unit/ccls/translation_table_test.rb +40 -0
  265. data/test/unit/ccls/unit_test.rb +21 -0
  266. data/test/unit/ccls/user_test.rb +156 -0
  267. data/test/unit/ccls/vital_status_test.rb +36 -0
  268. data/test/unit/ccls/zip_code_test.rb +55 -0
  269. metadata +633 -0
@@ -0,0 +1,74 @@
1
+ #
2
+ # Simply extracted some code to clean up model.
3
+ # I'd like to do this to all of the really big classes
4
+ # but let's see how this goes first.
5
+ #
6
+ module StudySubjectPii
7
+ def self.included(base)
8
+ # Must delay the calls to these ActiveRecord methods
9
+ # or it will raise many "undefined method"s.
10
+ base.class_eval do
11
+
12
+ # TODO include maiden_name just in case is mother???
13
+ def childs_names
14
+ [first_name, middle_name, last_name ]
15
+ end
16
+
17
+ # Returns string containing study_subject's first, middle and last initials
18
+ def initials
19
+ childs_names.delete_if(&:blank?).collect{|s|s.chars.first}.join()
20
+ end
21
+
22
+ # Returns string containing study_subject's first, middle and last name
23
+ # Use delete_if(&:blank?) instead of compact, which only removes nils.
24
+ def full_name
25
+ fullname = childs_names.delete_if(&:blank?).join(' ')
26
+ ( fullname.blank? ) ? '[name not available]' : fullname
27
+ end
28
+
29
+ def fathers_names
30
+ [father_first_name, father_middle_name, father_last_name ]
31
+ end
32
+
33
+ # Returns string containing study_subject's father's first, middle and last name
34
+ def fathers_name
35
+ fathersname = fathers_names.delete_if(&:blank?).join(' ')
36
+ ( fathersname.blank? ) ? '[name not available]' : fathersname
37
+ end
38
+
39
+ def mothers_names
40
+ [mother_first_name, mother_middle_name, mother_last_name ]
41
+ end
42
+
43
+ # Returns string containing study_subject's mother's first, middle and last name
44
+ # TODO what? no maiden name?
45
+ def mothers_name
46
+ mothersname = mothers_names.delete_if(&:blank?).join(' ')
47
+ ( mothersname.blank? ) ? '[name not available]' : mothersname
48
+ end
49
+
50
+ def guardians_names
51
+ [guardian_first_name, guardian_middle_name, guardian_last_name ]
52
+ end
53
+
54
+ # Returns string containing study_subject's guardian's first, middle and last name
55
+ def guardians_name
56
+ guardiansname = guardians_names.delete_if(&:blank?).join(' ')
57
+ ( guardiansname.blank? ) ? '[name not available]' : guardiansname
58
+ end
59
+
60
+ #
61
+ # TODO I hate this. It is revolting. More? Yes, please.
62
+ #
63
+ # I don't know if I still need this
64
+ # commented out 20101014
65
+ # uncommented 20101014
66
+ def dob # overwrite default dob method for formatting
67
+ # added to_date to fix sqlite3 quirk which doesn't (why am I using sqlite3?) old comment?
68
+ # differentiate between times and dates.
69
+ read_attribute(:dob).try(:to_s,:dob).try(:to_date)
70
+ end
71
+
72
+ end # class_eval
73
+ end # included
74
+ end # StudySubjectPii
@@ -0,0 +1,25 @@
1
+ #
2
+ # Simply extracted some code to clean up model.
3
+ # I'd like to do this to all of the really big classes
4
+ # but let's see how this goes first.
5
+ #
6
+ module StudySubjectRaces
7
+ def self.included(base)
8
+ # Must delay the calls to these ActiveRecord methods
9
+ # or it will raise many "undefined method"s.
10
+ base.class_eval do
11
+
12
+ has_many :subject_races
13
+ has_many :races, :through => :subject_races
14
+
15
+ accepts_nested_attributes_for :subject_races,
16
+ :allow_destroy => true,
17
+ :reject_if => proc{|attributes| attributes['race_id'].blank? }
18
+
19
+ def race_names
20
+ races.collect(&:to_s).join(', ')
21
+ end
22
+
23
+ end # class_eval
24
+ end # included
25
+ end # StudySubjectRaces
@@ -0,0 +1,260 @@
1
+ # This has gotton out of control. While it certainly still functions,
2
+ # I would advise that search commands be a bit more concise as most
3
+ # are only used in one location.
4
+ class StudySubjectSearch < Search
5
+
6
+ self.searchable_attributes += [ :races, :types, :vital_statuses, :q,
7
+ :sample_outcome, :interview_outcome,
8
+ :projects, :has_gift_card, :patid,
9
+ :abstracts_count
10
+ ]
11
+
12
+ self.attr_accessors += [ :search_gift_cards, :abstracts_count ]
13
+
14
+ # self.valid_orders.merge!({ # NO!
15
+ # @valid_orders.merge!({ # NO!
16
+ self.valid_orders = self.valid_orders.merge({
17
+ :id => 'study_subjects.id', # must remove any possible ambiguity
18
+ :childid => 'childid',
19
+ :last_name => 'last_name',
20
+ :first_name => 'first_name',
21
+ :dob => 'dob',
22
+ :studyid => 'patid',
23
+ :priority => 'recruitment_priority',
24
+ :sample_outcome => 'homex_outcomes.sample_outcome_id',
25
+ :sample_outcome_on => 'homex_outcomes.sample_outcome_on',
26
+ :patid => 'patid',
27
+ :abstracts_count => nil,
28
+ :interview_outcome_on => 'homex_outcomes.interview_outcome_on',
29
+ :sample_sent_on => nil,
30
+ :sample_received_on => nil,
31
+ :number => 'gift_cards.number',
32
+ :issued_on => 'gift_cards.issued_on'
33
+ #
34
+ # TODO this isn't true no more. gotta add another join
35
+ #
36
+ # :sent_to_subject_on => 'samples.sent_to_subject_on',
37
+ # :received_by_ccls_at => 'samples.received_by_ccls_at'
38
+ })
39
+
40
+ def study_subjects
41
+ require_dependency 'gift_card.rb' unless GiftCard
42
+ @subjects ||= StudySubject.send(
43
+ (paginate?)?'paginate':'all',{
44
+ :select => select,
45
+ :group => group,
46
+ :having => having,
47
+ :order => search_order,
48
+ :joins => joins,
49
+ :conditions => conditions
50
+ }.merge(
51
+ (paginate?)?{
52
+ :per_page => per_page||25,
53
+ :page => page||1
54
+ }:{}
55
+ )
56
+ )
57
+ end
58
+ alias_method :subjects, :study_subjects
59
+
60
+ private # THIS IS REQUIRED
61
+
62
+ # TODO as is not true
63
+ # I don't think that sorting by these fields is ever done.
64
+ # def samples_joins
65
+ # "JOIN samples ON study_subjects.id " <<
66
+ # "= samples.study_subject_id" if %w( sent_to_subject_on received_by_ccls_at ).include?(@order)
67
+ # end
68
+
69
+ def vital_statuses_joins
70
+ "INNER JOIN vital_statuses ON vital_statuses.id " <<
71
+ "= study_subjects.vital_status_id" unless vital_statuses.blank?
72
+ end
73
+
74
+ def vital_statuses_conditions
75
+ ['vital_statuses.key IN (:vital_statuses)', { :vital_statuses => vital_statuses }
76
+ ] unless vital_statuses.blank?
77
+ end
78
+
79
+ def patid_conditions
80
+ ['patid = :patid', {:patid => patid}] unless patid.blank?
81
+ end
82
+
83
+
84
+ def races_joins
85
+ # "INNER JOIN races ON races.id = study_subjects.race_id" unless races.blank?
86
+ "LEFT JOIN subject_races ON study_subjects.id = subject_races.study_subject_id LEFT JOIN races ON races.id = subject_races.race_id" unless races.blank?
87
+ end
88
+
89
+ #>> study_subjects = StudySubject.find(:all, :joins => "left join samples on study_subjects.id = samples.study_subject_id", :group => 'study_subjects.id', :having => ["sample_ids LIKE '%?%'",1], :select => "study_subjects.id, GROUP_CONCAT(samples.id) as sample_ids")
90
+ #=> [#<StudySubject id: 1>, #<StudySubject id: 2014>]
91
+
92
+ def races_groups
93
+ 'study_subjects.id' unless races.blank?
94
+ end
95
+
96
+ def races_selects
97
+ "study_subjects.*, CONCAT('|',GROUP_CONCAT(races.description SEPARATOR '|'),'|') as race_descriptions" unless races.blank?
98
+ end
99
+
100
+ def races_havings
101
+ unless races.blank?
102
+ c = []
103
+ v = {}
104
+ races.each_with_index do |race,i|
105
+ c << "race_descriptions LIKE :r#{i}"
106
+ v["r#{i}".to_sym] = "%|#{race}|%"
107
+ end
108
+ [ c.join(' OR '), v ]
109
+ end
110
+ end
111
+
112
+
113
+ def types_joins
114
+ "INNER JOIN subject_types ON subject_types.id " <<
115
+ "= study_subjects.subject_type_id" unless types.blank?
116
+ end
117
+
118
+ def types_conditions
119
+ ['subject_types.description IN (:types)', { :types => types }
120
+ ] unless types.blank?
121
+ end
122
+
123
+ def gift_card_joins
124
+ # A study_subject has many gift cards so this may pose a problem
125
+ "LEFT JOIN gift_cards ON gift_cards.study_subject_id = study_subjects.id" if(
126
+ search_gift_cards || %w( number issued_on ).include?(@order))
127
+ end
128
+
129
+ def q_conditions
130
+ unless q.blank?
131
+ c = []
132
+ v = {}
133
+ q.to_s.split(/\s+/).each_with_index do |t,i|
134
+ c.push("first_name LIKE :t#{i}")
135
+ c.push("last_name LIKE :t#{i}")
136
+ c.push("patid LIKE :t#{i}")
137
+ c.push("childid LIKE :t#{i}")
138
+ c.push("gift_cards.number LIKE :t#{i}") if search_gift_cards
139
+ v["t#{i}".to_sym] = "%#{t}%"
140
+ end
141
+ [ "( #{c.join(' OR ')} )", v ]
142
+ end
143
+ end
144
+
145
+ def gift_card_conditions
146
+ unless has_gift_card.nil?
147
+ if has_gift_card
148
+ ["gift_cards.id IS NOT NULL"]
149
+ else
150
+ ["gift_cards.id IS NULL"]
151
+ end
152
+ end
153
+ end
154
+
155
+ # join order matters and this MUST come before
156
+ # those that join on home_outcomes! Hmm?
157
+ # How? Added a sort to joins and an "a_" to this
158
+ def a_homex_outcome_joins
159
+ "LEFT JOIN homex_outcomes ON homex_outcomes.study_subject_id " <<
160
+ "= study_subjects.id" if( !sample_outcome.blank? ||
161
+ !interview_outcome.blank? ||
162
+ [ 'sample_outcome','sample_outcome_on','interview_outcome_on'].include?(@order) )
163
+ end
164
+
165
+ def sample_outcome_joins
166
+ "LEFT JOIN sample_outcomes ON sample_outcomes.id = " <<
167
+ "homex_outcomes.sample_outcome_id" unless
168
+ sample_outcome.blank?
169
+ end
170
+
171
+ def sample_outcome_conditions
172
+ unless sample_outcome.blank?
173
+ if sample_outcome =~ /^Complete$/i
174
+ # ['sample_outcomes.key = :sample_outcome',{:sample_outcome => sample_outcome}]
175
+ ['sample_outcomes.key IS NOT NULL && sample_outcomes.key NOT IN ("Sent","Pending")']
176
+ else
177
+ ["(sample_outcomes.key != 'Complete' " <<
178
+ "OR sample_outcomes.key IS NULL)"]
179
+ end
180
+ end
181
+ end
182
+
183
+ def interview_outcome_joins
184
+ "LEFT JOIN interview_outcomes ON interview_outcomes.id = " <<
185
+ "homex_outcomes.interview_outcome_id" unless
186
+ interview_outcome.blank?
187
+ end
188
+
189
+ def interview_outcome_conditions
190
+ unless interview_outcome.blank?
191
+ if interview_outcome =~ /^Complete$/i
192
+ ['interview_outcomes.key = :interview_outcome', {:interview_outcome => interview_outcome}]
193
+ else
194
+ ["(interview_outcomes.key != 'Complete'" <<
195
+ "OR interview_outcomes.key IS NULL)"]
196
+ end
197
+ end
198
+ end
199
+
200
+ def projects_joins
201
+ unless projects.blank?
202
+ s = ''
203
+ projects.keys.each do |id|
204
+ s << "JOIN enrollments proj_#{id} ON study_subjects.id "<<
205
+ "= proj_#{id}.study_subject_id AND proj_#{id}.project_id = #{id} "
206
+ end
207
+ s
208
+ end
209
+ end
210
+
211
+ def projects_conditions
212
+ unless projects.blank?
213
+ conditions = []
214
+ values = []
215
+ projects.each do |id,attributes|
216
+ attributes.each do |attr,val|
217
+ val = [val].flatten
218
+ if val.true_xor_false?
219
+ new_condition = case attr.to_s.downcase
220
+ when 'eligible'
221
+ "proj_#{id}.is_eligible " <<
222
+ ((val.true?)?'= 1':'!= 1')
223
+ when 'candidate'
224
+ "proj_#{id}.is_candidate " <<
225
+ ((val.true?)?'= 1':'!= 1')
226
+ when 'chosen'
227
+ "proj_#{id}.is_chosen " <<
228
+ ((val.true?)?'= 1':'!= 1')
229
+ when 'consented'
230
+ "proj_#{id}.consented " <<
231
+ ((val.true?)?'= 1':'!= 1')
232
+ when 'terminated'
233
+ "proj_#{id}.terminated_participation " <<
234
+ ((val.true?)?'= 1':'!= 1')
235
+ when 'closed'
236
+ "proj_#{id}.is_closed " <<
237
+ ((val.true?)?'= 1':'!= 1')
238
+ when 'completed'
239
+ "proj_#{id}.completed_on IS " <<
240
+ ((val.true?)?'NOT NULL':'NULL')
241
+ end # case attr.to_s.downcase
242
+ conditions << new_condition unless new_condition.blank?
243
+ end # if val.true_xor_false?
244
+ end # attributes.each
245
+ end # projects.each
246
+ [conditions.compact,values].flatten(1) unless conditions.empty?
247
+ end # unless projects.blank?
248
+ end # def projects_conditions
249
+
250
+ def abstracts_count_conditions
251
+ unless @abstracts_count.blank?
252
+ case @abstracts_count.to_s
253
+ when '0' then ["abstracts_count <= 0"]
254
+ when '1' then ["abstracts_count = 1"]
255
+ when '2' then ["abstracts_count = 2"]
256
+ end
257
+ end
258
+ end
259
+
260
+ end
@@ -0,0 +1,116 @@
1
+ #
2
+ # Simply extracted some code to clean up model.
3
+ # I'd like to do this to all of the really big classes
4
+ # but let's see how this goes first.
5
+ #
6
+ module StudySubjectValidations
7
+ def self.included(base)
8
+ # Must delay the calls to these ActiveRecord methods
9
+ # or it will raise many "undefined method"s.
10
+ base.class_eval do
11
+
12
+ validates_presence_of :subject_type_id
13
+ validates_presence_of :subject_type, :if => :subject_type_id
14
+
15
+ validate :presence_of_sex
16
+ # validates_inclusion_of :sex, :in => %w( M F DK ), :allow_blank => true
17
+ validates_inclusion_of :sex, :in => valid_sex_values, :allow_blank => true
18
+ validates_inclusion_of :do_not_contact, :in => [ true, false ]
19
+
20
+ validates_complete_date_for :reference_date, :allow_nil => true
21
+
22
+ validate :presence_of_dob, :unless => :is_mother?
23
+ validates_complete_date_for :dob, :allow_nil => true
24
+ validates_past_date_for :dob, :allow_nil => true
25
+ validates_complete_date_for :died_on, :allow_nil => true
26
+ validates_uniqueness_of :email, :icf_master_id, :state_id_no,
27
+ :state_registrar_no, :local_registrar_no, :gbid, :lab_no_wiemels,
28
+ :accession_no, :idno_wiemels, :studyid, :allow_nil => true
29
+
30
+ validates_format_of :email,
31
+ :with => /\A([-a-z0-9!\#$%&'*+\/=?^_`{|}~]+\.)*[-a-z0-9!\#$%&'*+\/=?^_`{|}~]+@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
32
+ :allow_blank => true
33
+
34
+ validate :presence_of_guardian_relationship_other,
35
+ :if => :guardian_relationship_is_other?
36
+
37
+ validates_presence_of :birth_city,
38
+ :if => :birth_country_is_united_states?
39
+ validates_presence_of :birth_state,
40
+ :if => :birth_country_is_united_states?
41
+
42
+ validates_length_of :case_control_type, :is => 1, :allow_nil => true
43
+
44
+ validates_length_of :ssn, :maximum => 250, :allow_nil => true
45
+ validates_uniqueness_of :ssn, :allow_nil => true
46
+ validates_format_of :ssn, :with => /\A\d{3}-\d{2}-\d{4}\z/,
47
+ :message => "should be formatted ###-##-####", :allow_nil => true
48
+
49
+ validates_length_of :birth_year,
50
+ :maximum => 4, :allow_blank => true
51
+ validates_length_of :newid,
52
+ :maximum => 6, :allow_blank => true
53
+ validates_length_of :icf_master_id,
54
+ :maximum => 9, :allow_blank => true
55
+ validates_length_of :childidwho, :idno_wiemels,
56
+ :generational_suffix, :father_generational_suffix,
57
+ :maximum => 10, :allow_blank => true
58
+ validates_length_of :lab_no_wiemels, :accession_no,
59
+ :maximum => 25, :allow_blank => true
60
+ validates_length_of :gbid,
61
+ :maximum => 26, :allow_blank => true
62
+ validates_length_of :first_name, :last_name,
63
+ :middle_name, :maiden_name, :guardian_relationship_other,
64
+ :father_first_name, :father_middle_name, :father_last_name,
65
+ :mother_first_name, :mother_middle_name, :mother_maiden_name, :mother_last_name,
66
+ :guardian_first_name, :guardian_middle_name, :guardian_last_name,
67
+ :mother_race_other, :father_race_other,
68
+ :birth_city, :birth_state, :birth_country,
69
+ :state_id_no, :state_registrar_no, :local_registrar_no,
70
+ :lab_no, :related_childid, :related_case_childid,
71
+ :maximum => 250, :allow_blank => true
72
+
73
+
74
+ validates_inclusion_of :mom_is_biomom, :dad_is_biodad,
75
+ :in => YNDK.valid_values, :allow_nil => true
76
+
77
+
78
+ # custom validation for custom message without standard attribute prefix
79
+ def presence_of_sex
80
+ if sex.blank?
81
+ errors.add(:sex, ActiveRecord::Error.new(
82
+ self, :base, :blank, {
83
+ :message => "No sex has been chosen." } ) )
84
+ end
85
+ end
86
+
87
+ protected
88
+
89
+ def birth_country_is_united_states?
90
+ birth_country == 'United States'
91
+ end
92
+
93
+ # custom validation for custom message without standard attribute prefix
94
+ def presence_of_guardian_relationship_other
95
+ if guardian_relationship_other.blank?
96
+ errors.add(:guardian_relationship_other, ActiveRecord::Error.new(
97
+ self, :base, :blank, {
98
+ :message => "You must specify a relationship with 'other relationship' is selected." } ) )
99
+ end
100
+ end
101
+
102
+ # custom validation for custom message without standard attribute prefix
103
+ def presence_of_dob
104
+ if dob.blank?
105
+ errors.add(:dob, ActiveRecord::Error.new(
106
+ self, :base, :blank, {
107
+ :message => "Date of birth can't be blank." } ) )
108
+ end
109
+ end
110
+
111
+ end # class_eval
112
+ end # included
113
+ end # StudySubjectValidations
114
+
115
+ __END__
116
+