view_mapper 0.3.3 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/README.rdoc +3 -1
  2. data/VERSION +1 -1
  3. data/lib/view_mapper.rb +1 -0
  4. data/lib/view_mapper/belongs_to_parent_models.rb +12 -26
  5. data/lib/view_mapper/has_many_child_models.rb +9 -9
  6. data/lib/view_mapper/model_info.rb +56 -18
  7. data/lib/view_mapper/views/belongs_to/belongs_to_view.rb +14 -0
  8. data/lib/view_mapper/views/belongs_to_auto_complete/belongs_to_auto_complete_view.rb +9 -2
  9. data/lib/view_mapper/views/has_many/templates/helper.rb +1 -1
  10. data/lib/view_mapper/views/has_many/templates/view_child_form.html.erb +1 -1
  11. data/lib/view_mapper/views/has_many/templates/view_form.html.erb +1 -1
  12. data/lib/view_mapper/views/has_many_existing/has_many_existing_view.rb +126 -0
  13. data/lib/view_mapper/views/has_many_existing/templates/model.rb +21 -0
  14. data/lib/view_mapper/views/has_many_existing/templates/view_child_form.html.erb +16 -0
  15. data/lib/view_mapper/views/has_many_existing/templates/view_form.html.erb +20 -0
  16. data/lib/view_mapper/views/has_many_existing/templates/view_show.html.erb +26 -0
  17. data/test/generators/scaffold_for_view/scaffold_for_view_generator_test.rb +15 -15
  18. data/test/generators/view_for/view_for_generator_test.rb +18 -18
  19. data/test/model_info_test.rb +91 -20
  20. data/test/test_helper.rb +75 -105
  21. data/test/views/auto_complete/auto_complete_test.rb +104 -102
  22. data/test/views/auto_complete/expected_templates/edit.html.erb +6 -6
  23. data/test/views/auto_complete/expected_templates/expected_routes.rb +1 -1
  24. data/test/views/auto_complete/expected_templates/index.html.erb +10 -10
  25. data/test/views/auto_complete/expected_templates/new.html.erb +5 -5
  26. data/test/views/auto_complete/expected_templates/show.html.erb +6 -6
  27. data/test/views/auto_complete/expected_templates/{testies.html.erb → test_models.html.erb} +1 -1
  28. data/test/views/auto_complete/expected_templates/test_models_controller.rb +89 -0
  29. data/test/views/belongs_to/belongs_to_test.rb +238 -202
  30. data/test/views/belongs_to/expected_templates/_form.html.erb +4 -4
  31. data/test/views/belongs_to/expected_templates/child_model.rb +10 -0
  32. data/test/views/belongs_to/expected_templates/create_child_models.rb +18 -0
  33. data/test/views/belongs_to/expected_templates/edit.html.erb +4 -4
  34. data/test/views/belongs_to/expected_templates/index.html.erb +11 -11
  35. data/test/views/belongs_to/expected_templates/new.html.erb +3 -3
  36. data/test/views/belongs_to/expected_templates/show.html.erb +7 -7
  37. data/test/views/belongs_to_auto_complete/belongs_to_auto_complete_test.rb +440 -406
  38. data/test/views/belongs_to_auto_complete/expected_templates/_form.html.erb +4 -4
  39. data/test/views/belongs_to_auto_complete/expected_templates/child_model.rb +16 -0
  40. data/test/views/belongs_to_auto_complete/expected_templates/{some_other_models.html.erb → child_models.html.erb} +1 -1
  41. data/test/views/belongs_to_auto_complete/expected_templates/child_models_controller.rb +89 -0
  42. data/test/views/belongs_to_auto_complete/expected_templates/create_child_models.rb +18 -0
  43. data/test/views/belongs_to_auto_complete/expected_templates/edit.html.erb +4 -4
  44. data/test/views/belongs_to_auto_complete/expected_templates/expected_routes.rb +2 -2
  45. data/test/views/belongs_to_auto_complete/expected_templates/index.html.erb +11 -11
  46. data/test/views/belongs_to_auto_complete/expected_templates/new.html.erb +3 -3
  47. data/test/views/belongs_to_auto_complete/expected_templates/show.html.erb +7 -7
  48. data/test/views/has_many/expected_templates/_form.html.erb +8 -8
  49. data/test/views/has_many/expected_templates/{_person.html.erb → _second_child_model.html.erb} +5 -5
  50. data/test/views/has_many/expected_templates/create_parent_models.rb +16 -0
  51. data/test/views/has_many/expected_templates/edit.html.erb +4 -4
  52. data/test/views/has_many/expected_templates/index.html.erb +7 -7
  53. data/test/views/has_many/expected_templates/new.html.erb +3 -3
  54. data/test/views/has_many/expected_templates/{parent.rb → parent_model.rb} +5 -5
  55. data/test/views/has_many/expected_templates/show.html.erb +15 -15
  56. data/test/views/has_many/has_many_view_test.rb +334 -292
  57. data/test/views/has_many_existing/expected_templates/_assignment.html.erb +14 -0
  58. data/test/views/has_many_existing/expected_templates/_form.html.erb +16 -0
  59. data/test/views/{has_many/expected_templates/create_parents.rb → has_many_existing/expected_templates/create_programmers.rb} +3 -3
  60. data/test/views/has_many_existing/expected_templates/edit.html.erb +11 -0
  61. data/test/views/has_many_existing/expected_templates/index.html.erb +20 -0
  62. data/test/views/has_many_existing/expected_templates/new.html.erb +10 -0
  63. data/test/views/has_many_existing/expected_templates/programmer.rb +10 -0
  64. data/test/views/has_many_existing/expected_templates/show.html.erb +20 -0
  65. data/test/views/has_many_existing/has_many_existing_test.rb +495 -0
  66. data/test/views/paperclip/expected_templates/{create_testies.rb → create_test_models.rb} +3 -3
  67. data/test/views/paperclip/expected_templates/edit.html.erb +4 -4
  68. data/test/views/paperclip/expected_templates/index.html.erb +10 -10
  69. data/test/views/paperclip/expected_templates/new.html.erb +3 -3
  70. data/test/views/paperclip/expected_templates/show.html.erb +8 -8
  71. data/test/views/paperclip/expected_templates/{testy.rb → test_model.rb} +1 -1
  72. data/test/views/paperclip/paperclip_view_test.rb +254 -226
  73. data/view_mapper.gemspec +43 -27
  74. metadata +64 -37
  75. data/test/views/auto_complete/expected_templates/actual_index +0 -26
  76. data/test/views/auto_complete/expected_templates/testies_controller.rb +0 -89
  77. data/test/views/belongs_to/expected_templates/create_some_other_models.rb +0 -18
  78. data/test/views/belongs_to/expected_templates/some_other_model.rb +0 -10
  79. data/test/views/belongs_to_auto_complete/expected_templates/create_some_other_models.rb +0 -18
  80. data/test/views/belongs_to_auto_complete/expected_templates/some_other_model.rb +0 -16
  81. data/test/views/belongs_to_auto_complete/expected_templates/some_other_models_controller.rb +0 -89
@@ -45,7 +45,9 @@ This is the same as view_for, but will also generate a new model at the same tim
45
45
 
46
46
  {belongs_to}[http://patshaughnessy.net/2010/1/25/creating-associations-to-existing-data-part-1-belongs_to-scaffolding]: Generates scaffolding that allows you to select an existing, associated model.
47
47
 
48
- belongs_to_auto_complete: Generates scaffolding that allows you to select an existing, associated model using auto_complete.
48
+ {belongs_to_auto_complete}[http://patshaughnessy.net/2010/2/13/creating-associations-to-existing-data-part-2-belongs_to-with-auto_complete]: Generates scaffolding that allows you to select an existing, associated model using auto_complete.
49
+
50
+ {has_many_existing}[http://patshaughnessy.net/2010/4/4/creating-associations-to-existing-data-part-3-has_many-through-scaffolding]: Generates scaffolding for a complex form to edit two models that have a has_many, :through association with a third model. Use this if you have a many-many relationship with existing data.
49
51
 
50
52
  == Examples
51
53
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.3
1
+ 0.3.4
@@ -9,3 +9,4 @@ require 'view_mapper/views/paperclip/paperclip_view'
9
9
  require 'view_mapper/views/has_many/has_many_view'
10
10
  require 'view_mapper/views/belongs_to/belongs_to_view'
11
11
  require 'view_mapper/views/belongs_to_auto_complete/belongs_to_auto_complete_view'
12
+ require 'view_mapper/views/has_many_existing/has_many_existing_view'
@@ -1,20 +1,6 @@
1
1
  module ViewMapper
2
2
  module BelongsToParentModels
3
3
 
4
- def manifest
5
- m = super.edit do |action|
6
- action unless is_model_dependency_action(action) || !valid
7
- end
8
- if valid
9
- m.template(
10
- "view_form.html.erb",
11
- File.join('app/views', controller_class_path, controller_file_name, "_form.html.erb")
12
- )
13
- add_model_actions(m) unless view_only?
14
- end
15
- m
16
- end
17
-
18
4
  def add_model_actions(m)
19
5
  m.directory(File.join('test/fixtures', class_path))
20
6
  m.template 'model.erb', File.join('app/models', class_path, "#{file_name}.rb")
@@ -70,30 +56,30 @@ module ViewMapper
70
56
  end
71
57
  return false
72
58
  end
73
- parents.reject! { |parent_model| !validate_parent_model(parent_model) }
59
+ parents.reject! { |parent_model| !validate_parent_model(parent_model, class_name, view_only? ? model : nil) }
74
60
  @parent_models = parents
75
61
  !parents.empty?
76
62
  end
77
63
 
78
- def validate_parent_model(parent_model)
64
+ def validate_parent_model(parent_model, child_model_name, child_model, check_setter_method = false)
79
65
  parent_model_name = parent_model.name
80
66
  if !parent_model.valid?
81
67
  logger.error parent_model.error
82
68
  return false
83
- elsif view_only? && !model.belongs_to?(parent_model_name)
84
- logger.warning "Model #{model.name} does not belong to model #{parent_model_name}."
69
+ elsif child_model && !child_model.belongs_to?(parent_model_name)
70
+ logger.warning "Model #{child_model.name} does not belong to model #{parent_model_name}."
85
71
  return false
86
- elsif view_only? && !model.has_method?(virtual_attribute_for(parent_model))
87
- logger.warning "Model #{model.name} does not have a method #{virtual_attribute_for(parent_model)}."
72
+ elsif child_model && !child_model.has_method?(virtual_attribute_for(parent_model))
73
+ logger.warning "Model #{child_model.name} does not have a method #{virtual_attribute_for(parent_model)}."
88
74
  return false
89
- elsif view_only? && !model.has_method?(virtual_attribute_setter_for(parent_model))
90
- logger.warning "Model #{model.name} does not have a method #{virtual_attribute_setter_for(parent_model)}."
75
+ elsif child_model && check_setter_method && !child_model.has_method?(virtual_attribute_setter_for(parent_model))
76
+ logger.warning "Model #{child_model.name} does not have a method #{virtual_attribute_setter_for(parent_model)}."
91
77
  return false
92
- elsif view_only? && !model.has_foreign_key_for?(parent_model_name)
93
- logger.warning "Model #{class_name} does not contain a foreign key for #{parent_model_name}."
78
+ elsif child_model && !child_model.has_foreign_key_for?(parent_model_name)
79
+ logger.warning "Model #{child_model.name} does not contain a foreign key for #{parent_model_name}."
94
80
  return false
95
- elsif !parent_model.has_many?(class_name.pluralize)
96
- logger.warning "Model #{parent_model_name} does not contain a has_many association for #{class_name}."
81
+ elsif !parent_model.has_many?(child_model_name.pluralize)
82
+ logger.warning "Model #{parent_model_name} does not contain a has_many association for #{child_model_name}."
97
83
  return false
98
84
  elsif !parent_model.has_method?(field_for(parent_model)) && !parent_model.has_column?(field_for(parent_model))
99
85
  logger.warning "Model #{parent_model_name} does not have a #{field_for(parent_model)} attribute."
@@ -82,26 +82,26 @@ module ViewMapper
82
82
  end
83
83
  return false
84
84
  end
85
- cms.reject! { |child_model| !validate_child_model(child_model) }
85
+ cms.reject! { |child_model| !validate_child_model(child_model, class_name, view_only? ? model : nil) }
86
86
  @child_models = cms
87
87
  !cms.empty?
88
88
  end
89
89
 
90
- def validate_child_model(child_model)
90
+ def validate_child_model(child_model, parent_model_name, parent_model)
91
91
  if !child_model.valid?
92
92
  logger.error child_model.error
93
93
  return false
94
- elsif view_only? && !model.accepts_nested_attributes_for?(child_model)
95
- logger.warning "Model #{model.name} does not accept nested attributes for model #{child_model.name}."
94
+ elsif parent_model && !parent_model.accepts_nested_attributes_for?(child_model)
95
+ logger.warning "Model #{parent_model.name} does not accept nested attributes for model #{child_model.name}."
96
96
  return false
97
97
  else
98
- if child_model.has_many?(class_name.pluralize) || child_model.has_and_belongs_to_many?(class_name.pluralize)
98
+ if child_model.has_many?(parent_model_name.pluralize) || child_model.has_and_belongs_to_many?(parent_model_name.pluralize)
99
99
  true
100
- elsif !child_model.belongs_to?(class_name)
101
- logger.warning "Model #{child_model.name} does not contain a belongs_to association for #{class_name}."
100
+ elsif !child_model.belongs_to?(parent_model_name)
101
+ logger.warning "Model #{child_model.name} does not contain a belongs_to association for #{parent_model_name}."
102
102
  return false
103
- elsif !child_model.has_foreign_key_for?(class_name)
104
- logger.warning "Model #{child_model.name} does not contain a foreign key for #{class_name}."
103
+ elsif !child_model.has_foreign_key_for?(parent_model_name)
104
+ logger.warning "Model #{child_model.name} does not contain a foreign key for #{parent_model_name}."
105
105
  return false
106
106
  end
107
107
  end
@@ -1,10 +1,10 @@
1
1
  module ViewMapper
2
2
  class ModelInfo
3
3
 
4
- attr_reader :model
5
- attr_reader :name
6
- attr_reader :attributes
7
- attr_reader :error
4
+ attr_reader :model
5
+ attr_accessor :through_model # has_many :through => XYZ
6
+ attr_reader :name
7
+ attr_reader :error
8
8
 
9
9
  def initialize(model_name)
10
10
  @model = find_model(model_name)
@@ -52,18 +52,47 @@ module ViewMapper
52
52
  end
53
53
 
54
54
  def child_models
55
- model_info_array_for_association(:has_many)
55
+ @child_models ||= model_info_array_for_association(:has_many)
56
56
  end
57
57
 
58
58
  def parent_models
59
- model_info_array_for_association(:belongs_to)
59
+ @parent_models ||= model_info_array_for_association(:belongs_to)
60
60
  end
61
61
 
62
- def model_info_array_for_association(association_type)
63
- model.reflections.select { |key, value| value.macro == association_type }.collect do |kvpair|
64
- kvpair[0].to_s.singularize
65
- end.sort.collect do |model_name|
66
- ModelInfo.new model_name
62
+ def has_many_through_models
63
+ @has_many_through_models ||= model_info_array_for_association(:has_many, ActiveRecord::Reflection::ThroughReflection)
64
+ end
65
+
66
+ def find_through_model(source_model_name)
67
+ reflections_for_association(:has_many, ActiveRecord::Reflection::ThroughReflection).each do |kvpair|
68
+ reflection_model_name = kvpair[0].to_s.singularize
69
+ if reflection_model_name == source_model_name.underscore
70
+ reflection = kvpair[1]
71
+ return ModelInfo.new(reflection.options[:through].to_s.singularize)
72
+ end
73
+ end
74
+ nil
75
+ end
76
+
77
+ def reflections_for_association(association_type, type)
78
+ model.reflections.select { |key, value| value.macro == association_type && value.is_a?(type) }
79
+ end
80
+
81
+ def model_info_from_reflection(reflection_model_name, reflection)
82
+ model_info = ModelInfo.new(reflection_model_name)
83
+ if reflection.is_a? ActiveRecord::Reflection::ThroughReflection
84
+ model_info.through_model = ModelInfo.new reflection.options[:through].to_s.singularize
85
+ end
86
+ model_info
87
+ end
88
+
89
+ def model_info_array_for_association(association_type, type = ActiveRecord::Reflection::AssociationReflection)
90
+ reflections_for_association(association_type, type).collect do |kvpair|
91
+ reflection_model_name = kvpair[0].to_s.singularize
92
+ reflection = kvpair[1]
93
+ model_info_from_reflection(reflection_model_name, reflection)
94
+ end.sort do |a, b|
95
+ a.name <=> b.name
67
96
  end
68
97
  end
69
98
 
@@ -77,18 +106,27 @@ module ViewMapper
77
106
  end
78
107
 
79
108
  def belongs_to?(parent_model_name)
80
- has_association_for? :belongs_to, parent_model_name
109
+ !association_for(:belongs_to, parent_model_name).nil?
81
110
  end
82
111
 
83
112
  def has_many?(child_model_name)
84
- has_association_for? :has_many, child_model_name
113
+ !association_for(:has_many, child_model_name).nil?
85
114
  end
86
115
 
87
116
  def has_and_belongs_to_many?(model_name)
88
- has_association_for? :has_and_belongs_to_many, model_name
117
+ !association_for(:has_and_belongs_to_many, model_name).nil?
118
+ end
119
+
120
+ def has_many_through?(model_name)
121
+ reflection = association_for(:has_many, model_name.pluralize)
122
+ reflection && reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
89
123
  end
90
124
 
91
125
  def has_foreign_key_for?(parent_model_name)
126
+ !foreign_key_for(parent_model_name).nil?
127
+ end
128
+
129
+ def foreign_key_for(parent_model_name)
92
130
  model.columns.detect { |col| is_foreign_key_for?(col, parent_model_name) }
93
131
  end
94
132
 
@@ -140,10 +178,10 @@ module ViewMapper
140
178
  end
141
179
  end
142
180
 
143
- def has_association_for?(association, model_name)
144
- !model.reflections.values.detect do |reflection|
181
+ def association_for(association, model_name)
182
+ model.reflections.values.detect do |reflection|
145
183
  reflection.name == model_name.underscore.to_sym && reflection.macro == association
146
- end.nil?
184
+ end
147
185
  end
148
186
 
149
187
  def is_paperclip_column?(col)
@@ -161,7 +199,7 @@ module ViewMapper
161
199
  def has_column_for_attachment(attachment, paperclip_col)
162
200
  has_column = model.columns.map {|col| col.name}.include?(paperclip_col)
163
201
  if !has_column
164
- @error = "Column \'#{paperclip_col}\' does not exist. First run script/generate paperclip #{name.downcase} #{attachment}."
202
+ @error = "Column \'#{paperclip_col}\' does not exist. First run script/generate paperclip #{name.underscore} #{attachment}."
165
203
  end
166
204
  has_column
167
205
  end
@@ -11,6 +11,20 @@ module ViewMapper
11
11
  [ BelongsToView.source_root, File.expand_path(source_root), File.join(self.class.lookup('model').path, 'templates') ]
12
12
  end
13
13
 
14
+ def manifest
15
+ m = super.edit do |action|
16
+ action unless is_model_dependency_action(action) || !valid
17
+ end
18
+ if valid
19
+ m.template(
20
+ "view_form.html.erb",
21
+ File.join('app/views', controller_class_path, controller_file_name, "_form.html.erb")
22
+ )
23
+ add_model_actions(m) unless view_only?
24
+ end
25
+ m
26
+ end
27
+
14
28
  def validate
15
29
  super
16
30
  @valid &&= validate_parent_models
@@ -12,8 +12,15 @@ module ViewMapper
12
12
  end
13
13
 
14
14
  def manifest
15
- m = super
15
+ m = super.edit do |action|
16
+ action unless is_model_dependency_action(action) || !valid
17
+ end
16
18
  if valid
19
+ m.template(
20
+ "view_form.html.erb",
21
+ File.join('app/views', controller_class_path, controller_file_name, "_form.html.erb")
22
+ )
23
+ add_model_actions(m) unless view_only?
17
24
  parent_models.reverse.each do |parent_model|
18
25
  m.route :name => 'connect',
19
26
  :path => auto_complete_for_method(parent_model),
@@ -34,7 +41,7 @@ module ViewMapper
34
41
  @valid &&= validate_parent_models
35
42
  end
36
43
 
37
- def validate_parent_model(parent_model)
44
+ def validate_parent_model(parent_model, child_model_name, child_model, check_setter_method = true)
38
45
  valid = super
39
46
  if valid && !parent_model.has_column?(field_for(parent_model))
40
47
  logger.warning "Model #{parent_model.name} does not have a #{field_for(parent_model)} column."
@@ -1,7 +1,7 @@
1
1
  module <%= controller_class_name %>Helper
2
2
 
3
3
  def remove_child_link(name, form_builder)
4
- form_builder.hidden_field(:_delete) + link_to_function(name, "remove_child(this)")
4
+ form_builder.hidden_field(:_destroy) + link_to_function(name, "remove_child(this)")
5
5
  end
6
6
 
7
7
  def add_child_link(name, child, form_builder)
@@ -6,7 +6,7 @@
6
6
  </p>
7
7
  <% end -%>
8
8
  <p>
9
- <%%= f.hidden_field :_delete, :class => 'delete' %>
9
+ <%%= f.hidden_field :_destroy, :class => 'delete' %>
10
10
  <%%= remove_child_link 'remove', f %>
11
11
  </p>
12
12
  </div>
@@ -15,6 +15,6 @@
15
15
  </div>
16
16
 
17
17
  <p>
18
- <%%= add_child_link 'Add a <%= child_model.name %>', '<%= child_model.name.underscore %>', f %>
18
+ <%%= add_child_link 'Add <%= child_model.name %>', '<%= child_model.name.underscore %>', f %>
19
19
  </p>
20
20
  <% end -%>
@@ -0,0 +1,126 @@
1
+ module ViewMapper
2
+ module HasManyExistingView
3
+
4
+ include BelongsToParentModels
5
+ include HasManyChildModels
6
+
7
+ def self.source_root
8
+ File.expand_path(File.dirname(__FILE__) + "/templates")
9
+ end
10
+
11
+ def source_roots_for_view
12
+ [
13
+ HasManyExistingView.source_root,
14
+ HasManyView.source_root,
15
+ File.expand_path(source_root),
16
+ File.join(self.class.lookup('model').path, 'templates')
17
+ ]
18
+ end
19
+
20
+ def manifest
21
+ m = super.edit do |action|
22
+ action unless is_child_model_action?(action)
23
+ end
24
+ add_through_models_manifest(m)
25
+ m
26
+ end
27
+
28
+ def add_through_models_manifest(m)
29
+ add_child_model_actions(m) if valid && !view_only?
30
+ add_through_model_forms(m) if valid
31
+ m
32
+ end
33
+
34
+ def add_through_model_forms(m)
35
+ m.template(
36
+ "view_show.html.erb",
37
+ File.join('app/views', controller_class_path, controller_file_name, "show.html.erb"),
38
+ { :assigns => { :has_many_through_models => has_many_through_models } }
39
+ )
40
+ m.template(
41
+ "view_form.html.erb",
42
+ File.join('app/views', controller_class_path, controller_file_name, "_form.html.erb")
43
+ )
44
+ has_many_through_models.each do |hmt_model|
45
+ m.template(
46
+ "view_child_form.html.erb",
47
+ File.join('app/views', controller_class_path, controller_file_name, "_#{hmt_model.through_model.name.underscore}.html.erb"),
48
+ { :assigns => { :hmt_model => hmt_model } }
49
+
50
+ )
51
+ end
52
+ m.file('nested_attributes.js', 'public/javascripts/nested_attributes.js')
53
+ m
54
+ end
55
+
56
+ def validate
57
+ super
58
+ @valid &&= validate_hmt_models
59
+ end
60
+
61
+ def has_many_through_models
62
+ @hmt_models ||= find_hmt_models
63
+ end
64
+
65
+ def find_hmt_models
66
+ if view_param
67
+ view_param.split(',').collect do |param|
68
+ hmt_model_info_from_param(param)
69
+ end
70
+ elsif view_only?
71
+ model.has_many_through_models
72
+ else
73
+ []
74
+ end
75
+ end
76
+
77
+ def hmt_model_info_from_param(param)
78
+ if /(.*)\[(.*)\]/.match(param)
79
+ hmt_model = ModelInfo.new($1.singularize)
80
+ select_parent_by hmt_model, $2
81
+ else
82
+ hmt_model = ModelInfo.new(param.singularize)
83
+ end
84
+ hmt_model
85
+ end
86
+
87
+ def validate_hmt_models
88
+ models = has_many_through_models
89
+ if models.empty?
90
+ if view_only?
91
+ logger.error "No has_many through associations exist in class #{model.name}."
92
+ else
93
+ logger.error "No has_many through association specified."
94
+ end
95
+ return false
96
+ end
97
+ models.reject! { |hmt_model| !validate_hmt_model(hmt_model) }
98
+ @hmt_models = models
99
+ !models.empty?
100
+ end
101
+
102
+ def validate_hmt_model(hmt_model)
103
+ if !hmt_model.valid?
104
+ logger.error hmt_model.error
105
+ return false
106
+ elsif !hmt_model.has_many_through?(class_name)
107
+ logger.warning "Model #{hmt_model.name} does not contain a has_many through association for #{class_name}."
108
+ return false
109
+ end
110
+
111
+ hmt_model.through_model = hmt_model.find_through_model(class_name) if hmt_model.through_model.nil?
112
+ if !hmt_model.through_model.valid?
113
+ logger.error hmt_model.through_model.error
114
+ return false
115
+ elsif !validate_parent_model(hmt_model, hmt_model.through_model.name, hmt_model.through_model)
116
+ return false
117
+ elsif !validate_child_model(hmt_model.through_model, class_name, view_only? ? model : nil)
118
+ return false
119
+ elsif !validate_child_model(hmt_model.through_model, hmt_model.name, nil)
120
+ return false
121
+ end
122
+ true
123
+ end
124
+
125
+ end
126
+ end
@@ -0,0 +1,21 @@
1
+ class <%= class_name %> < ActiveRecord::Base
2
+ <% has_many_through_models.each do |hmt_model| -%>
3
+ <% attribs = Array.new(hmt_model.through_model.attributes) -%>
4
+ <% attribs << hmt_model.through_model.foreign_key_for(hmt_model.name) -%>
5
+ has_many :<%= hmt_model.name.underscore.pluralize %>, :through => :<%= hmt_model.through_model.name.underscore.pluralize %>
6
+ has_many :<%= hmt_model.through_model.name.underscore.pluralize %>
7
+ accepts_nested_attributes_for :<%= hmt_model.through_model.name.underscore.pluralize %>,
8
+ :allow_destroy => true<% if attribs.size > 0 %>,<% end %>
9
+ <% if attribs.size > 0 -%>
10
+ <% if attribs.size == 1 -%>
11
+ :reject_if => proc { |attrs| attrs['<%= attribs[0].name %>'].blank? }
12
+ <% elsif -%>
13
+ :reject_if => proc { |attrs|
14
+ <% attribs.each_with_index do |attr, i| -%>
15
+ attrs['<%= attr.name %>'].blank?<% unless i == attribs.size-1 %> &&<% end %>
16
+ <% end -%>
17
+ }
18
+ <% end -%>
19
+ <% end -%>
20
+ <% end -%>
21
+ end