dry_crud 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/MIT-LICENSE +19 -0
  2. data/README.rdoc +208 -0
  3. data/Rakefile +101 -0
  4. data/VERSION +1 -0
  5. data/rails_generators/dry_crud/USAGE +1 -0
  6. data/rails_generators/dry_crud/dry_crud_generator.rb +22 -0
  7. data/rails_generators/dry_crud/templates/INSTALL +13 -0
  8. data/rails_generators/dry_crud/templates/app/controllers/crud_controller.rb +182 -0
  9. data/rails_generators/dry_crud/templates/app/helpers/crud_helper.rb +45 -0
  10. data/rails_generators/dry_crud/templates/app/helpers/standard_helper.rb +209 -0
  11. data/rails_generators/dry_crud/templates/app/views/crud/_attrs.html.erb +1 -0
  12. data/rails_generators/dry_crud/templates/app/views/crud/_form.html.erb +1 -0
  13. data/rails_generators/dry_crud/templates/app/views/crud/_list.html.erb +1 -0
  14. data/rails_generators/dry_crud/templates/app/views/crud/edit.html.erb +8 -0
  15. data/rails_generators/dry_crud/templates/app/views/crud/index.html.erb +14 -0
  16. data/rails_generators/dry_crud/templates/app/views/crud/new.html.erb +7 -0
  17. data/rails_generators/dry_crud/templates/app/views/crud/show.html.erb +9 -0
  18. data/rails_generators/dry_crud/templates/app/views/layouts/crud.html.erb +20 -0
  19. data/rails_generators/dry_crud/templates/app/views/shared/_labeled.html.erb +5 -0
  20. data/rails_generators/dry_crud/templates/lib/crud_callbacks.rb +55 -0
  21. data/rails_generators/dry_crud/templates/lib/render_inheritable.rb +118 -0
  22. data/rails_generators/dry_crud/templates/lib/standard_form_builder.rb +161 -0
  23. data/rails_generators/dry_crud/templates/lib/standard_table_builder.rb +104 -0
  24. data/rails_generators/dry_crud/templates/public/stylesheets/crud.css +91 -0
  25. data/rails_generators/dry_crud/templates/test/crud_test_model.rb +124 -0
  26. data/rails_generators/dry_crud/templates/test/functional/crud_controller_test_helper.rb +172 -0
  27. data/rails_generators/dry_crud/templates/test/functional/crud_test_models_controller_test.rb +96 -0
  28. data/rails_generators/dry_crud/templates/test/unit/crud_helper_test.rb +57 -0
  29. data/rails_generators/dry_crud/templates/test/unit/render_inheritable_test.rb +161 -0
  30. data/rails_generators/dry_crud/templates/test/unit/standard_form_builder_test.rb +83 -0
  31. data/rails_generators/dry_crud/templates/test/unit/standard_helper_test.rb +183 -0
  32. data/rails_generators/dry_crud/templates/test/unit/standard_table_builder_test.rb +99 -0
  33. data/test/templates/app/controllers/ajax_controller.rb +7 -0
  34. data/test/templates/app/controllers/application_controller.rb +11 -0
  35. data/test/templates/app/controllers/cities_controller.rb +13 -0
  36. data/test/templates/app/controllers/people_controller.rb +7 -0
  37. data/test/templates/app/helpers/people_helper.rb +7 -0
  38. data/test/templates/app/models/city.rb +13 -0
  39. data/test/templates/app/models/person.rb +9 -0
  40. data/test/templates/app/views/ajax/_hello.html.erb +1 -0
  41. data/test/templates/app/views/ajax/ajax.js.rjs +1 -0
  42. data/test/templates/app/views/ajax/index.html.erb +9 -0
  43. data/test/templates/app/views/cities/_attrs.html.erb +1 -0
  44. data/test/templates/app/views/cities/_form.html.erb +4 -0
  45. data/test/templates/app/views/cities/_hello.html.erb +1 -0
  46. data/test/templates/app/views/cities/_list.html.erb +5 -0
  47. data/test/templates/config/routes.rb +11 -0
  48. data/test/templates/db/migrate/20100511174904_create_people_and_cities.rb +23 -0
  49. data/test/templates/test/fixtures/cities.yml +11 -0
  50. data/test/templates/test/fixtures/people.yml +14 -0
  51. data/test/templates/test/functional/cities_controller_test.rb +35 -0
  52. data/test/templates/test/functional/people_controller_test.rb +30 -0
  53. metadata +127 -0
@@ -0,0 +1,104 @@
1
+ # A simple helper to easily define tables listing several rows of the same data type.
2
+ #
3
+ # Example Usage:
4
+ # StandardTableBuilder.table(entries, template) do |t|
5
+ # t.col('My Header', :class => 'css') {|e| link_to 'Show', e }
6
+ # t.attrs :name, :city
7
+ # end
8
+ class StandardTableBuilder
9
+ attr_reader :entries, :cols, :template
10
+
11
+ # Delegate called methods to template.
12
+ # including StandardHelper would lead to problems with indirectly called methods.
13
+ delegate :content_tag, :format_attr, :column_type, :belongs_to_association,
14
+ :captionize, :tr_alt, :to => :template
15
+
16
+ def initialize(entries, template)
17
+ @entries = entries
18
+ @template = template
19
+ @cols = []
20
+ end
21
+
22
+ # Convenience method to directly generate a table. Renders a row for each entry in entries.
23
+ # Takes a block that gets the table object as parameter for configuration.
24
+ # Returns the generated html for the table.
25
+ def self.table(entries, template)
26
+ t = new(entries, template)
27
+ yield t
28
+ t.to_html
29
+ end
30
+
31
+ # Define a column for the table with the given header, the html_options used for
32
+ # each td and a block rendering the contents of a cell for the current entry.
33
+ # The columns appear in the order they are defined.
34
+ def col(header = '', html_options = {}, &block)
35
+ @cols << Col.new(header, html_options, @template, block)
36
+ end
37
+
38
+ # Convenience method to add one or more attribute columns.
39
+ # The attribute name will become the header, the cells will contain
40
+ # the formatted attribute value for the current entry.
41
+ def attrs(*attrs)
42
+ attrs.each do |a|
43
+ col(captionize(a, entry_class), :class => align_class(a)) { |e| format_attr(e, a) }
44
+ end
45
+ end
46
+
47
+ # Renders the table as HTML.
48
+ def to_html
49
+ content_tag :table, :class => 'list' do
50
+ [html_header] +
51
+ entries.collect { |e| html_row(e) }
52
+ end
53
+ end
54
+
55
+ # Returns css classes used for alignment of the cell data.
56
+ # Based on the column type of the attribute.
57
+ def align_class(attr)
58
+ entry = entries.first
59
+ case column_type(entry, attr)
60
+ when :integer, :float, :decimal
61
+ 'right_align' unless belongs_to_association(entry, attr)
62
+ when :boolean
63
+ 'center_align'
64
+ end
65
+ end
66
+
67
+ private
68
+
69
+ def html_header
70
+ content_tag :tr do
71
+ cols.collect { |c| c.html_header }
72
+ end
73
+ end
74
+
75
+ def html_row(entry)
76
+ tr_alt do
77
+ cols.collect { |c| c.html_cell(entry) }
78
+ end
79
+ end
80
+
81
+ def entry_class
82
+ entries.first.class
83
+ end
84
+
85
+ # Helper class to store column information.
86
+ class Col < Struct.new(:header, :html_options, :template, :block) #:nodoc:
87
+
88
+ delegate :content_tag, :to => :template
89
+
90
+ def content(entry)
91
+ block.call(entry)
92
+ end
93
+
94
+ def html_header
95
+ content_tag :th, header
96
+ end
97
+
98
+ def html_cell(entry)
99
+ content_tag :td, content(entry), html_options
100
+ end
101
+
102
+ end
103
+
104
+ end
@@ -0,0 +1,91 @@
1
+ body, div, p, td, th {
2
+ font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
3
+ font-size: 11pt;
4
+ }
5
+
6
+ td {
7
+ vertical-align: top;
8
+ }
9
+
10
+ tr.even {
11
+ background-color: #DDD;
12
+ }
13
+
14
+ tr.odd {
15
+ background-color: #EEE;
16
+ }
17
+
18
+ table.list {}
19
+
20
+ /* div rendered if no entries available for list */
21
+ div.list {}
22
+
23
+ .right_align {
24
+ text-align: right;
25
+ }
26
+
27
+ .center_align {
28
+ text-align: center;
29
+ }
30
+
31
+ .labeled {
32
+ vertical-align: top;
33
+ margin: 1pt;
34
+ }
35
+
36
+ .labeled .caption {
37
+ font-style: italic;
38
+ width: 120pt;
39
+ padding-right: 5pt;
40
+ float: left;
41
+ }
42
+
43
+ .labeled .value {
44
+ margin-left: 125pt;
45
+ }
46
+
47
+ .labeled .value p {
48
+ margin: 0px;
49
+ }
50
+
51
+ .attributes {}
52
+
53
+ a.action {
54
+ color: red;
55
+ text-decoration: none;
56
+ }
57
+
58
+ a:hover.action {
59
+ text-decoration: underline;
60
+ }
61
+
62
+ a:visited.action {
63
+ color: red;
64
+ }
65
+
66
+ #flash_notice {
67
+ color: #663333;
68
+ }
69
+
70
+ div.errorExplanation {
71
+ border: solid 1px #999999;
72
+ margin: 10pt;
73
+ padding: 5pt;
74
+ background-color: #FFBBBB;
75
+ }
76
+
77
+ .errorExplanation h2 {
78
+ font-size: 12pt;
79
+ margin-top: 0pt;
80
+ }
81
+
82
+ .errorExplanation ul {
83
+ margin-bottom: 5pt;
84
+ }
85
+
86
+ div.fieldWithErrors {
87
+ background-color: #FFBBBB;
88
+ display: inline-block;
89
+ padding: 2px;
90
+ }
91
+
@@ -0,0 +1,124 @@
1
+ class CrudTestModel < ActiveRecord::Base #:nodoc:
2
+ validates_presence_of :name
3
+
4
+ default_scope :order => 'name'
5
+
6
+ belongs_to :companion, :class_name => 'CrudTestModel'
7
+
8
+ def label
9
+ name
10
+ end
11
+ end
12
+
13
+ class CrudTestModelsController < CrudController #:nodoc:
14
+ HANDLE_PREFIX = 'handle_'
15
+
16
+ before_create :possibly_redirect
17
+ before_create :handle_name
18
+
19
+ before_render_new :possibly_redirect
20
+ before_render_new :set_companions
21
+
22
+ attr_reader :called_callbacks
23
+ attr_accessor :should_redirect
24
+
25
+ hide_action :called_callbacks, :should_redirect, :should_redirect=
26
+
27
+ private
28
+
29
+ # custom callback
30
+ def handle_name
31
+ if @entry.name == 'illegal'
32
+ flash[:error] = "illegal name"
33
+ return false
34
+ end
35
+ end
36
+
37
+ [:create, :update, :save, :destroy].each do |a|
38
+ callback = "before_#{a.to_s}"
39
+ send(callback.to_sym, :"#{HANDLE_PREFIX}#{callback}")
40
+ callback = "after_#{a.to_s}"
41
+ send(callback.to_sym, :"#{HANDLE_PREFIX}#{callback}")
42
+ end
43
+
44
+ def method_missing(sym, *args)
45
+ called_callback(sym.to_s[HANDLE_PREFIX.size..-1].to_sym) if sym.to_s.starts_with?(HANDLE_PREFIX)
46
+ end
47
+
48
+ def possibly_redirect
49
+ redirect_to :action => 'index' if should_redirect && !performed?
50
+ !should_redirect
51
+ end
52
+
53
+ def set_companions
54
+ @companions = CrudTestModel.all :conditions => {:human => true}
55
+ end
56
+
57
+ def called_callback(callback)
58
+ @called_callbacks ||= []
59
+ @called_callbacks << callback
60
+ end
61
+
62
+ end
63
+
64
+ ActionController::Routing::Routes.draw do |map|
65
+ map.resources :crud_test_models
66
+ end
67
+
68
+ # A simple test helper to prepare the test database with a CrudTestModel model.
69
+ module CrudTestHelper
70
+
71
+ protected
72
+
73
+ # Sets up the test database with a crud_test_models table.
74
+ # Look at the source to view the column definition.
75
+ def setup_db
76
+ silence_stream(STDOUT) do
77
+ ActiveRecord::Base.connection.create_table :crud_test_models, :force => true do |t|
78
+ t.string :name, :null => false, :limit => 50
79
+ t.string :whatever
80
+ t.integer :children
81
+ t.integer :companion_id
82
+ t.float :rating
83
+ t.decimal :income, :precision => 14, :scale => 2
84
+ t.date :birthdate
85
+ t.boolean :human, :default => true
86
+ t.text :remarks
87
+
88
+ t.timestamps
89
+ end
90
+ end
91
+ end
92
+
93
+ # Removes the crud_test_models table from the database.
94
+ def reset_db
95
+ [:crud_test_models].each do |table|
96
+ ActiveRecord::Base.connection.drop_table(table) rescue nil
97
+ end
98
+ end
99
+
100
+ # Creates 6 dummy entries for the crud_test_models table.
101
+ def create_test_data
102
+ (1..6).inject(nil) {|prev, i| create(i, prev) }
103
+ end
104
+
105
+ # Fixture-style accessor method to get CrudTestModel instances by name
106
+ def crud_test_models(name)
107
+ CrudTestModel.find_by_name(name.to_s)
108
+ end
109
+
110
+ private
111
+
112
+ def create(index, companion)
113
+ c = (index + 64).chr * 5
114
+ CrudTestModel.create!(:name => c,
115
+ :children => index,
116
+ :companion => companion,
117
+ :rating => "#{index}.#{index}".to_f,
118
+ :income => 10000000 * index + 0.1 * index,
119
+ :birthdate => "#{1900 + 10 * index}-#{index}-#{index}",
120
+ :human => index % 2 == 0,
121
+ :remarks => "#{c} #{c} #{c}\n" * 3)
122
+ end
123
+
124
+ end
@@ -0,0 +1,172 @@
1
+ # A module to include into your functional tests for your crud controller subclasses.
2
+ # Simply implement the two methods :test_entry and :test_entry_attrs to test the basic
3
+ # crud functionality. Override the test methods if you changed the behaviour in your subclass
4
+ # controller.
5
+ module CrudControllerTestHelper
6
+
7
+ def test_index
8
+ get :index
9
+ assert_response :success
10
+ assert_template 'index'
11
+ assert_not_nil assigns(:entries)
12
+ end
13
+
14
+ def test_index_xml
15
+ get :index, :format => 'xml'
16
+ assert_response :success
17
+ assert_not_nil assigns(:entries)
18
+ assert @response.body.starts_with?("<?xml")
19
+ end
20
+
21
+ def test_show
22
+ get :show, :id => test_entry.id
23
+ assert_response :success
24
+ assert_template 'show'
25
+ assert_equal test_entry, assigns(:entry)
26
+ end
27
+
28
+ def test_show_xml
29
+ get :show, :id => test_entry.id, :format => 'xml'
30
+ assert_response :success
31
+ assert_equal test_entry, assigns(:entry)
32
+ assert @response.body.starts_with?("<?xml")
33
+ end
34
+
35
+ def test_show_with_not_existing_id_raises_RecordNotFound
36
+ assert_raise(ActiveRecord::RecordNotFound) do
37
+ get :show, :id => 9999
38
+ end
39
+ end
40
+
41
+ def test_show_without_id_redirects_to_index
42
+ get :show
43
+ assert_redirected_to_index
44
+ end
45
+
46
+ def test_new
47
+ get :new
48
+ assert_response :success
49
+ assert_template 'new'
50
+ assert assigns(:entry).new_record?
51
+ end
52
+
53
+ def test_create
54
+ assert_difference("#{model_class.name}.count") do
55
+ post :create, model_identifier => test_entry_attrs
56
+ end
57
+ assert_redirected_to assigns(:entry)
58
+ assert ! assigns(:entry).new_record?
59
+ assert_test_attrs_equal
60
+ end
61
+
62
+ def test_create_with_wrong_http_method_redirects
63
+ get :create, model_identifier => test_entry_attrs
64
+ assert_redirected_to_index
65
+
66
+ put :create, model_identifier => test_entry_attrs
67
+ assert_redirected_to_index
68
+
69
+ delete :create, model_identifier => test_entry_attrs
70
+ assert_redirected_to_index
71
+ end
72
+
73
+ def test_create_xml
74
+ assert_difference("#{model_class.name}.count") do
75
+ post :create, model_identifier => test_entry_attrs, :format => 'xml'
76
+ end
77
+ assert_response :success
78
+ assert @response.body.starts_with?("<?xml")
79
+ end
80
+
81
+ def test_edit
82
+ get :edit, :id => test_entry.id
83
+ assert_response :success
84
+ assert_template 'edit'
85
+ assert_equal test_entry, assigns(:entry)
86
+ end
87
+
88
+ def test_edit_without_id_raises_RecordNotFound
89
+ assert_raise(ActiveRecord::RecordNotFound) do
90
+ get :edit
91
+ end
92
+ end
93
+
94
+ def test_update
95
+ assert_no_difference("#{model_class.name}.count") do
96
+ put :update, :id => test_entry.id, model_identifier => test_entry_attrs
97
+ end
98
+ assert_test_attrs_equal
99
+ assert_redirected_to assigns(:entry)
100
+ end
101
+
102
+ def test_update_with_wrong_http_method_redirects
103
+ get :update, :id => test_entry.id, model_identifier => test_entry_attrs
104
+ assert_redirected_to_index
105
+
106
+ delete :update, :id => test_entry.id, model_identifier => test_entry_attrs
107
+ assert_redirected_to_index
108
+ end
109
+
110
+ def test_update_xml
111
+ assert_no_difference("#{model_class.name}.count") do
112
+ put :update, :id => test_entry.id, model_identifier => test_entry_attrs, :format => 'xml'
113
+ end
114
+ assert_response :success
115
+ assert_equal "", @response.body.strip
116
+ end
117
+
118
+ def test_destroy
119
+ assert_difference("#{model_class.name}.count", -1) do
120
+ delete :destroy, :id => test_entry.id
121
+ end
122
+ assert_redirected_to_index
123
+ end
124
+
125
+ def test_destroy_with_wrong_http_method_redirects
126
+ get :destroy, :id => test_entry.id
127
+ assert_redirected_to_index
128
+
129
+ put :destroy, :id => test_entry.id
130
+ assert_redirected_to_index
131
+ end
132
+
133
+ def test_destroy_xml
134
+ assert_difference("#{model_class.name}.count", -1) do
135
+ delete :destroy, :id => test_entry.id, :format => 'xml'
136
+ end
137
+ assert_response :success
138
+ assert_equal "", @response.body.strip
139
+ end
140
+
141
+ protected
142
+
143
+ def assert_redirected_to_index
144
+ assert_redirected_to :action => 'index'
145
+ end
146
+
147
+ def assert_test_attrs_equal
148
+ test_entry_attrs.each do |key, value|
149
+ actual = assigns(:entry).send(key)
150
+ assert_equal value, actual, "#{key} is expected to be <#{value.inspect}>, got <#{actual.inspect}>"
151
+ end
152
+ end
153
+
154
+ def model_class
155
+ @controller.controller_name.classify.constantize
156
+ end
157
+
158
+ def model_identifier
159
+ @controller.controller_name.singularize.to_sym
160
+ end
161
+
162
+ # Test object used in several tests
163
+ def test_entry
164
+ raise "Implement this method in your test class"
165
+ end
166
+
167
+ # Attribute hash used in several tests
168
+ def test_entry_attrs
169
+ raise "Implement this method in your test class"
170
+ end
171
+
172
+ end
@@ -0,0 +1,96 @@
1
+ require 'test_helper'
2
+ require 'crud_test_model'
3
+ require File.join(File.dirname(__FILE__), 'crud_controller_test_helper')
4
+
5
+ class CrudTestModelsControllerTest < ActionController::TestCase
6
+
7
+ include CrudControllerTestHelper
8
+ include CrudTestHelper
9
+
10
+ attr_accessor :models
11
+
12
+ setup :reset_db, :setup_db, :create_test_data
13
+
14
+ teardown :reset_db
15
+
16
+ def test_setup
17
+ assert_equal 6, CrudTestModel.count
18
+ assert_equal CrudTestModelsController, @controller.class
19
+ assert_recognizes({:controller => 'crud_test_models', :action => 'index'}, '/crud_test_models')
20
+ assert_recognizes({:controller => 'crud_test_models', :action => 'show', :id => '1'}, '/crud_test_models/1')
21
+ assert_equal %w(index show new create edit update destroy).to_set, CrudTestModelsController.send(:action_methods)
22
+ end
23
+
24
+ def test_index
25
+ super
26
+ assert_equal 6, assigns(:entries).size
27
+ assert_equal assigns(:entries).sort_by {|a| a.name }, assigns(:entries)
28
+ end
29
+
30
+ def test_new
31
+ super
32
+ assert assigns(:companions)
33
+ end
34
+
35
+ def test_create
36
+ super
37
+ assert_equal [:before_create, :before_save, :after_save, :after_create], @controller.called_callbacks
38
+ end
39
+
40
+ def test_update
41
+ super
42
+ assert_equal [:before_update, :before_save, :after_save, :after_update], @controller.called_callbacks
43
+ end
44
+
45
+ def test_destroy
46
+ super
47
+ assert_equal [:before_destroy, :after_destroy], @controller.called_callbacks
48
+ end
49
+
50
+ def test_create_with_before_callback
51
+ assert_no_difference("#{model_class.name}.count") do
52
+ post :create, :crud_test_model => {:name => 'illegal', :children => 2}
53
+ end
54
+ assert_template 'new'
55
+ assert assigns(:entry).new_record?
56
+ assert assigns(:companions)
57
+ assert flash[:error].present?
58
+ assert_equal 'illegal', assigns(:entry).name
59
+ assert_nil @controller.called_callbacks
60
+ end
61
+
62
+ def test_create_with_before_callback_redirect
63
+ @controller.should_redirect = true
64
+ assert_no_difference("#{model_class.name}.count") do
65
+ post :create, :crud_test_model => {:name => 'illegal', :children => 2}
66
+ end
67
+ assert_redirected_to :action => 'index'
68
+ assert_nil @controller.called_callbacks
69
+ end
70
+
71
+ def test_new_with_before_render_callback_redirect_does_not_set_companions
72
+ @controller.should_redirect = true
73
+ get :new
74
+ assert_redirected_to :action => 'index'
75
+ assert_nil assigns(:companions)
76
+ end
77
+
78
+
79
+ protected
80
+
81
+ def test_entry
82
+ crud_test_models(:AAAAA)
83
+ end
84
+
85
+ def test_entry_attrs
86
+ {:name => 'foo',
87
+ :children => 42,
88
+ :companion_id => 3,
89
+ :rating => 99.99,
90
+ :income => 2.42,
91
+ :birthdate => '31-12-1999'.to_date,
92
+ :human => true,
93
+ :remarks => "some custom\n\tremarks"}
94
+ end
95
+
96
+ end
@@ -0,0 +1,57 @@
1
+ require 'test_helper'
2
+ require 'crud_test_model'
3
+
4
+ class CrudHelperTest < ActionView::TestCase
5
+
6
+ include StandardHelper
7
+ include CrudTestHelper
8
+
9
+ setup :reset_db, :setup_db, :create_test_data
10
+ teardown :reset_db
11
+
12
+ def model_class
13
+ CrudTestModel
14
+ end
15
+
16
+ test "standard crud table" do
17
+ @entries = CrudTestModel.all
18
+ t = crud_table
19
+ assert_match /(<tr.+?<\/tr>){7}/m, t
20
+ assert_match /(<th.+?<\/th>){14}/m, t
21
+ assert_match /(<a href.+?<\/a>.*?){18}/m, t
22
+ end
23
+
24
+ test "custom crud table" do
25
+ @entries = CrudTestModel.all
26
+ t = crud_table do |t|
27
+ t.attrs :name, :children, :companion_id
28
+ t.col("head") {|e| content_tag :span, e.income.to_s }
29
+ end
30
+ assert_match /(<tr.+?<\/tr>){7}/m, t
31
+ assert_match /(<th.+?<\/th>){4}/m, t
32
+ assert_match /(<span>.+?<\/span>.*?){6}/m, t
33
+ assert_no_match /(<a href.+?<\/a>.*?)/m, t
34
+ end
35
+
36
+ test "crud form" do
37
+ @entry = CrudTestModel.first
38
+ f = capture { crud_form }
39
+
40
+ assert_match /form .*?action="\/crud_test_models\/#{@entry.id}"/, f
41
+ assert_match /input .*?name="crud_test_model\[name\]" .*?type="text"/, f
42
+ assert_match /input .*?name="crud_test_model\[whatever\]" .*?type="text"/, f
43
+ assert_match /input .*?name="crud_test_model\[children\]" .*?type="text"/, f
44
+ assert_match /input .*?name="crud_test_model\[rating\]" .*?type="text"/, f
45
+ assert_match /input .*?name="crud_test_model\[income\]" .*?type="text"/, f
46
+ assert_match /select .*?name="crud_test_model\[birthdate\(1i\)\]"/, f
47
+ assert_match /input .*?name="crud_test_model\[human\]" .*?type="checkbox"/, f
48
+ assert_match /select .*?name="crud_test_model\[companion_id\]"/, f
49
+ assert_match /textarea .*?name="crud_test_model\[remarks\]"/, f
50
+ end
51
+
52
+ test "default attributes do not include id" do
53
+ assert_equal [:name, :whatever, :children, :companion_id, :rating, :income,
54
+ :birthdate, :human, :remarks, :created_at, :updated_at], default_attrs
55
+ end
56
+
57
+ end