Reputation: 41
In Michael Hartl's Ruby on Rails Tutorial, 2nd Ed, chapter 9's exercise 6, says:
Signed-in users have no reason to access the new and create actions in the Users controller. Arrange for such users to be redirected to the root URL if they do try to hit those pages.
How does one write the rspec test for this? I tried this
describe "POST on Users#create" do
before { post users_path }
specify { response.should redirect_to(root_path) }
end
I have tried using a do/end block, adding a hash of user attributes, etc. The snippet above was added to line #162 in the official sample code. All of them give me this error:
Failures:
1) Authentication authorization as non-admin user POST on Users#create
Failure/Error: before { post users_path }
AbstractController::DoubleRenderError:
Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like "redirect_to(...) and return".
# ./app/controllers/users_controller.rb:27:in `create'
# ./spec/requests/authentication_pages_spec.rb:72:in `block (5 levels) in <top (required)>'
Finished in 2.72 seconds
88 examples, 1 failure
As for the actual objective which is to limit access to the new and create actions in the Users controller, I solved them by adding this line:
admin_user if signed_in?
I know this works because I tested it by hand. The only problem is I am unable to write an rspec test for it. The code I have created as I follow this tutorial is available at github.
Why am I getting this error? What am I doing wrong? What is the solution? Thank you.
Upvotes: 1
Views: 1285
Reputation: 29419
I'm just going through the tutorial myself and am at this exact exercise, so I'm certainly not an expert. However, I'm interpreting the request differently than you are. As I understand it, the request is to redirect to the root page if any signed-in user attempts the User new or create operations, not just non-admins.
In any event, the most elegant solution that I've seen is to use the before_filter as described in https://stackoverflow.com/a/11287798/1008891
Upvotes: 2
Reputation: 41
Paul, thank you for the clue. I solved the problem.
I tried to solve the objective by adding
admin_user if signed_in?
While this appeared to work in the browser, there was something else going on in the background. After looking more closely into my create action, this is the change I made and the rspec test began to work:
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 6e0fec8..53f8325 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -8,8 +8,8 @@ class UsersController < ApplicationController
end
def new
- admin_user if signed_in?
- @user = User.new
+ signed_in? ? admin_user : @user = User.new
+ #@user = User.new
end
def show
@@ -17,14 +17,17 @@ class UsersController < ApplicationController
end
def create
- admin_user if signed_in?
- @user = User.create(params[:user])
- if @user.save
- sign_in @user
- flash[:success] = "Welcome to the Sample App!"
- redirect_to @user
- else
- render 'new'
+ if signed_in?
+ admin_user
+ else
+ @user = User.create(params[:user])
+ if @user.save
+ sign_in @user
+ flash[:success] = "Welcome to the Sample App!"
+ redirect_to @user
+ else
+ render 'new'
+ end
end
end
The solution is to enclose the code into full if/else blocks. If I don't, it appears the code continues in as evidenced by the create action. This was not an issue so much with the new action because after the simplistic ternary, it only assigned an instance variable.
In conclusion, I just need a very good clue from Paul, and a good night's sleep. Thank you.
Upvotes: 1