Skip to content
This repository
Browse code

Scaffolded controller specs are compatible with Rails 4

* Rails 4 introduces
  [strong_parameters](https://github.com/rails/strong_parameters).
* If a model is scaffolded with attributes (e.g., `rails generate
  scaffold foo bar:string`), Rails will generate a controller that only
  accepts `bar`. This means that the controller spec must be aware of
  the specific parameters when sending PUT (update) requests.
* Furthermore if a model is scaffolded with attributes, Rails generates
  a controller that *requires* the #presence of attributes. This means
  we cannot send in an empty Hash, as the Rails framework will return a
  400 Bad Request.
  • Loading branch information...
commit 86b07996a990f19fc2769c182080894691d2fa79 1 parent be689da
Andy Lindeman alindeman authored
4 features/model_specs/errors_on.feature
@@ -8,7 +8,9 @@ Feature: errors_on
8 8 class ValidatingWidget < ActiveRecord::Base
9 9 self.table_name = :widgets
10 10 validates_presence_of :name
11   - attr_accessible :name
  11 +
  12 + # In Rails 4, mass assignment protection is implemented on controllers
  13 + attr_accessible :name if Rails.version < '4'
12 14
13 15 validates_length_of :name, :minimum => 10, :on => :publication
14 16 end
38 lib/generators/rspec/scaffold/scaffold_generator.rb
@@ -57,8 +57,42 @@ def copy_view(view)
57 57 File.join("spec/views", controller_file_path, "#{view}.html.#{options[:template_engine]}_spec.rb")
58 58 end
59 59
60   - def params
61   - "{'these' => 'params'}"
  60 + def example_valid_attributes
  61 + # Only take the first attribute so this hash does not become unweildy and large in the
  62 + # generated controller spec. It is the responsibility of the user to keep the the valid
  63 + # attributes method up-to-date as they add validations.
  64 + @example_valid_attributes ||=
  65 + if attributes.any?
  66 + { attributes.first.name => attributes.first.default.to_s }
  67 + else
  68 + { }
  69 + end
  70 + end
  71 +
  72 + def example_invalid_attributes
  73 + @example_invalid_attributes ||=
  74 + if attributes.any?
  75 + { attributes.first.name => "invalid value" }
  76 + else
  77 + { }
  78 + end
  79 + end
  80 +
  81 + def example_params_for_update
  82 + @example_params_for_update ||=
  83 + if example_valid_attributes.any?
  84 + example_valid_attributes
  85 + else
  86 + { "these" => "params" }
  87 + end
  88 + end
  89 +
  90 + def formatted_hash(hash)
  91 + formatted = hash.inspect
  92 + formatted.gsub!("{", "{ ")
  93 + formatted.gsub!("}", " }")
  94 + formatted.gsub!("=>", " => ")
  95 + formatted
62 96 end
63 97
64 98 # support for namespaced-resources
14 lib/generators/rspec/scaffold/templates/controller_spec.rb
@@ -24,7 +24,7 @@
24 24 # <%= class_name %>. As you add validations to <%= class_name %>, be sure to
25 25 # update the return value of this method accordingly.
26 26 def valid_attributes
27   - {}
  27 + <%= formatted_hash(example_valid_attributes) %>
28 28 end
29 29
30 30 # This should return the minimal set of values that should be in the session
@@ -91,14 +91,14 @@ def valid_session
91 91 it "assigns a newly created but unsaved <%= ns_file_name %> as @<%= ns_file_name %>" do
92 92 # Trigger the behavior that occurs when invalid params are submitted
93 93 <%= class_name %>.any_instance.stub(:save).and_return(false)
94   - post :create, {:<%= ns_file_name %> => {}}, valid_session
  94 + post :create, {:<%= ns_file_name %> => <%= formatted_hash(example_invalid_attributes) %>}, valid_session
95 95 assigns(:<%= ns_file_name %>).should be_a_new(<%= class_name %>)
96 96 end
97 97
98 98 it "re-renders the 'new' template" do
99 99 # Trigger the behavior that occurs when invalid params are submitted
100 100 <%= class_name %>.any_instance.stub(:save).and_return(false)
101   - post :create, {:<%= ns_file_name %> => {}}, valid_session
  101 + post :create, {:<%= ns_file_name %> => <%= formatted_hash(example_invalid_attributes) %>}, valid_session
102 102 response.should render_template("new")
103 103 end
104 104 end
@@ -112,8 +112,8 @@ def valid_session
112 112 # specifies that the <%= class_name %> created on the previous line
113 113 # receives the :update_attributes message with whatever params are
114 114 # submitted in the request.
115   - <%= class_name %>.any_instance.should_receive(:update_attributes).with(<%= params %>)
116   - put :update, {:id => <%= file_name %>.to_param, :<%= ns_file_name %> => <%= params %>}, valid_session
  115 + <%= class_name %>.any_instance.should_receive(:update_attributes).with(<%= formatted_hash(example_params_for_update) %>)
  116 + put :update, {:id => <%= file_name %>.to_param, :<%= ns_file_name %> => <%= formatted_hash(example_params_for_update) %>}, valid_session
117 117 end
118 118
119 119 it "assigns the requested <%= ns_file_name %> as @<%= ns_file_name %>" do
@@ -134,7 +134,7 @@ def valid_session
134 134 <%= file_name %> = <%= class_name %>.create! valid_attributes
135 135 # Trigger the behavior that occurs when invalid params are submitted
136 136 <%= class_name %>.any_instance.stub(:save).and_return(false)
137   - put :update, {:id => <%= file_name %>.to_param, :<%= ns_file_name %> => {}}, valid_session
  137 + put :update, {:id => <%= file_name %>.to_param, :<%= ns_file_name %> => <%= formatted_hash(example_invalid_attributes) %>}, valid_session
138 138 assigns(:<%= ns_file_name %>).should eq(<%= file_name %>)
139 139 end
140 140
@@ -142,7 +142,7 @@ def valid_session
142 142 <%= file_name %> = <%= class_name %>.create! valid_attributes
143 143 # Trigger the behavior that occurs when invalid params are submitted
144 144 <%= class_name %>.any_instance.stub(:save).and_return(false)
145   - put :update, {:id => <%= file_name %>.to_param, :<%= ns_file_name %> => {}}, valid_session
  145 + put :update, {:id => <%= file_name %>.to_param, :<%= ns_file_name %> => <%= formatted_hash(example_invalid_attributes) %>}, valid_session
146 146 response.should render_template("edit")
147 147 end
148 148 end
8 spec/generators/rspec/scaffold/scaffold_generator_spec.rb
@@ -14,6 +14,7 @@
14 14 before { run_generator %w(posts) }
15 15 it { should contain(/require 'spec_helper'/) }
16 16 it { should contain(/describe PostsController/) }
  17 + it { should contain(%({ "these" => "params" })) }
17 18 end
18 19
19 20 describe 'with --no-controller_specs' do
@@ -22,6 +23,13 @@
22 23 end
23 24 end
24 25
  26 + describe 'controller spec with attributes specified' do
  27 + subject { file('spec/controllers/posts_controller_spec.rb') }
  28 + before { run_generator %w(posts title:string) }
  29 +
  30 + it { should contain(%({ "title" => "MyString" })) }
  31 + end
  32 +
25 33 describe 'namespaced controller spec' do
26 34 subject { file('spec/controllers/admin/posts_controller_spec.rb') }
27 35 before { run_generator %w(admin/posts) }

0 comments on commit 86b0799

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