Skip to content
This repository
Browse code

Add polymorphic option to model generator

For instance,

    $ rails g model Product supplier:references{polymorphic}

generate model with `belongs_to :supplier, polymorphic: true` association and appropriate migration.

Also fix model_generator_test.rb#L196 and #L201
  • Loading branch information...
commit 94b230e189e7241b96dcbfb41ceabedf7cfd14ac 1 parent 51b055b
Aleksey Magusev authored June 25, 2012
2  activerecord/lib/rails/generators/active_record/model/templates/model.rb
... ...
@@ -1,7 +1,7 @@
1 1
 <% module_namespacing do -%>
2 2
 class <%= class_name %> < <%= parent_class_name.classify %>
3 3
 <% attributes.select {|attr| attr.reference? }.each do |attribute| -%>
4  
-  belongs_to :<%= attribute.name %>
  4
+  belongs_to :<%= attribute.name %><%= ', polymorphic: true' if attribute.polymorphic? %>
5 5
 <% end -%>
6 6
 <% if !accessible_attributes.empty? -%>
7 7
   attr_accessible <%= accessible_attributes.map {|a| ":#{a.name}" }.sort.join(', ') %>
14  railties/lib/rails/generators/generated_attribute.rb
@@ -35,7 +35,7 @@ def reference?(type)
35 35
 
36 36
         private
37 37
 
38  
-        # parse possible attribute options like :limit for string/text/binary/integer or :precision/:scale for decimals
  38
+        # parse possible attribute options like :limit for string/text/binary/integer, :precision/:scale for decimals or :polymorphic for references/belongs_to
39 39
         # when declaring options curly brackets should be used
40 40
         def parse_type_and_options(type)
41 41
           case type
@@ -43,6 +43,8 @@ def parse_type_and_options(type)
43 43
             return $1, :limit => $2.to_i
44 44
           when /decimal\{(\d+)[,.-](\d+)\}/
45 45
             return :decimal, :precision => $1.to_i, :scale => $2.to_i
  46
+          when /(references|belongs_to)\{polymorphic\}/
  47
+            return $1, :polymorphic => true
46 48
           else
47 49
             return type, {}
48 50
           end
@@ -92,13 +94,21 @@ def human_name
92 94
       end
93 95
 
94 96
       def index_name
95  
-        reference? ? "#{name}_id" : name
  97
+        if reference?
  98
+          polymorphic? ? %w(id type).map { |t| "#{name}_#{t}" } : "#{name}_id"
  99
+        else
  100
+          name
  101
+        end
96 102
       end
97 103
 
98 104
       def reference?
99 105
         self.class.reference?(type)
100 106
       end
101 107
 
  108
+      def polymorphic?
  109
+        self.attr_options.has_key?(:polymorphic)
  110
+      end
  111
+
102 112
       def has_index?
103 113
         @has_index
104 114
       end
23  railties/test/generators/generated_attribute_test.rb
@@ -102,22 +102,28 @@ def test_human_name
102 102
 
103 103
   def test_reference_is_true
104 104
     %w(references belongs_to).each do |attribute_type|
105  
-      assert_equal(
106  
-        true,
107  
-        create_generated_attribute(attribute_type).reference?
108  
-      )
  105
+      assert create_generated_attribute(attribute_type).reference?
109 106
     end
110 107
   end
111 108
 
112 109
   def test_reference_is_false
113 110
     %w(foo bar baz).each do |attribute_type|
114  
-      assert_equal(
115  
-        false,
116  
-        create_generated_attribute(attribute_type).reference?
117  
-      )
  111
+      assert !create_generated_attribute(attribute_type).reference?
118 112
     end
119 113
   end
120 114
 
  115
+  def test_polymorphic_reference_is_true
  116
+    %w(references belongs_to).each do |attribute_type|
  117
+      assert create_generated_attribute("#{attribute_type}{polymorphic}").polymorphic?
  118
+    end
  119
+  end
  120
+  
  121
+  def test_polymorphic_reference_is_false
  122
+    %w(foo bar baz).each do |attribute_type|
  123
+      assert !create_generated_attribute("#{attribute_type}{polymorphic}").polymorphic?
  124
+    end
  125
+  end
  126
+  
121 127
   def test_blank_type_defaults_to_string_raises_exception
122 128
     assert_equal :string, create_generated_attribute(nil, 'title').type
123 129
     assert_equal :string, create_generated_attribute("", 'title').type
@@ -126,5 +132,6 @@ def test_blank_type_defaults_to_string_raises_exception
126 132
   def test_handles_index_names_for_references
127 133
     assert_equal "post", create_generated_attribute('string', 'post').index_name
128 134
     assert_equal "post_id", create_generated_attribute('references', 'post').index_name
  135
+    assert_equal ["post_id", "post_type"], create_generated_attribute('references{polymorphic}', 'post').index_name
129 136
   end
130 137
 end
17  railties/test/generators/model_generator_test.rb
@@ -166,7 +166,7 @@ def test_migration_with_missing_attribute_type_and_with_index
166 166
   end
167 167
 
168 168
   def test_add_migration_with_attributes_index_declaration_and_attribute_options
169  
-    run_generator ["product", "title:string{40}:index", "content:string{255}", "price:decimal{5,2}:index", "discount:decimal{5,2}:uniq"]
  169
+    run_generator ["product", "title:string{40}:index", "content:string{255}", "price:decimal{5,2}:index", "discount:decimal{5,2}:uniq", "supplier:references{polymorphic}"]
170 170
 
171 171
     assert_migration "db/migrate/create_products.rb" do |content|
172 172
       assert_method :change, content do |up|
@@ -174,6 +174,7 @@ def test_add_migration_with_attributes_index_declaration_and_attribute_options
174 174
         assert_match(/t.string :title, limit: 40/, up)
175 175
         assert_match(/t.string :content, limit: 255/, up)
176 176
         assert_match(/t.decimal :price, precision: 5, scale: 2/, up)
  177
+        assert_match(/t.references :supplier, polymorphic: true/, up)
177 178
       end
178 179
       assert_match(/add_index :products, :title/, content)
179 180
       assert_match(/add_index :products, :price/, content)
@@ -193,15 +194,25 @@ def test_migration_without_timestamps
193 194
   end
194 195
 
195 196
   def test_model_with_references_attribute_generates_belongs_to_associations
196  
-    run_generator ["product", "name:string", "supplier_id:references"]
  197
+    run_generator ["product", "name:string", "supplier:references"]
197 198
     assert_file "app/models/product.rb", /belongs_to :supplier/
198 199
   end
199 200
 
200 201
   def test_model_with_belongs_to_attribute_generates_belongs_to_associations
201  
-    run_generator ["product", "name:string", "supplier_id:belongs_to"]
  202
+    run_generator ["product", "name:string", "supplier:belongs_to"]
202 203
     assert_file "app/models/product.rb", /belongs_to :supplier/
203 204
   end
204 205
 
  206
+  def test_model_with_polymorphic_references_attribute_generates_belongs_to_associations
  207
+    run_generator ["product", "name:string", "supplier:references{polymorphic}"]
  208
+    assert_file "app/models/product.rb", /belongs_to :supplier, polymorphic: true/
  209
+  end
  210
+
  211
+  def test_model_with_polymorphic_belongs_to_attribute_generates_belongs_to_associations
  212
+    run_generator ["product", "name:string", "supplier:belongs_to{polymorphic}"]
  213
+    assert_file "app/models/product.rb", /belongs_to :supplier, polymorphic: true/
  214
+  end
  215
+
205 216
   def test_migration_with_timestamps
206 217
     run_generator
207 218
     assert_migration "db/migrate/create_accounts.rb", /t.timestamps/

0 notes on commit 94b230e

Please sign in to comment.
Something went wrong with that request. Please try again.