Permalink
Browse files

Don't show links to unauthorized actions

We shouldn't' show the user links to actions we know they are not
authorized to perform.

In the process of implementing the view specs for this, I came across a
tricky issue with regards to stubbing the `policy` method in the view
(which is provided by pundit via a controller helper method). The
`verify_partial_doubles` setting in rspec was raising an error because
the view itself does not actually implement `policy`. Rails magic!

I thought I could trick it by passing a lambda named `policy` to the
view as a local variable but that did not work. Instead, I followed some
workarounds found here: rspec/rspec-rails#1076

Essentially in each view spec, we extend the view object to contain the
controller helper methods that we encounter in our views. Then, since
they are now technically present on the view object, we can stub them.
I'm not entirely comfortable with that solution since we're actually
changing the object under test, but I thought it was the best option.
The other things I considered were disabling partial double verification
in view specs with an around filter or testing these with feature specs.
  • Loading branch information...
1 parent 35a7396 commit 7443270b3f52364d7899cefd95f42735f50e79f1 @derekprior derekprior committed Jun 5, 2015
@@ -1,11 +1,18 @@
-<div class="row">
- <h3>To set up outcomes</h3>
-</div>
-<div class="row">
- <%=link_to "Adopt Default Outcomes",
- course_default_outcomes_path(course),
- method: :post %>
-</div>
-<div class="row">
- <%=link_to "Create Custom Outcomes", new_course_outcome_path(course) %>
-</div>
+<% if policy(course).create_outcomes? %>
+ <div class="row">
+ <h3>To set up outcomes</h3>
+ </div>
+
+ <div class="row">
+ <%=link_to "Adopt Default Outcomes",
+ course_default_outcomes_path(course),
+ method: :post %>
+ </div>
+
+ <div class="row">
+ <%=link_to "Create Custom Outcomes", new_course_outcome_path(course) %>
+ </div>
+<% else %>
+ <p>This course has no associated outcomes and you do not have permission
+ to add any.</p>
+<% end %>
@@ -9,7 +9,12 @@
<tr id="outcome-<%=outcome.id %>">
<td><%= outcome.name%></td>
<td><%= outcome.description%></td>
- <td><%= link_to "Add new assessment", new_outcome_assessment_path(outcome)%></td>
+ <td>
+ <% if policy(outcome).create_assessments? %>
+ <%= link_to "Add new assessment",
+ new_outcome_assessment_path(outcome) %>
+ <% end %>
+ </td>
<td><%= link_to "Details", outcome_path(outcome)%></td>
</tr>
<% end %>
@@ -23,5 +28,8 @@
<% end %>
</ul>
</div>
- <%= link_to "New custom outcome", new_course_outcome_path(course), class: "button" %>
+
+ <% if policy(course).create_outcomes? %>
+ <%= link_to "New custom outcome", new_course_outcome_path(course), class: "button" %>
+ <% end %>
<% end %>
@@ -2,8 +2,26 @@ module ViewSpecHelpers
def page
Capybara.string(rendered)
end
+
+ def stub_policy(methods)
+ allow(view).to receive(:policy).and_return(double("Policy", methods))
+ end
+
+ def initialize_controller_helper_methods(view)
+ view.extend ControllerHelperMethods
+ end
+
+ module ControllerHelperMethods
+ def policy(object)
+ raise "stub policy behavior to test this view"
+ end
+ end
end
RSpec.configure do |config|
config.include ViewSpecHelpers, type: :view
+
+ config.before(:each, type: :view) do
+ initialize_controller_helper_methods(view)
+ end
end
@@ -0,0 +1,21 @@
+require "rails_helper"
+
+describe "courses/_interstitial.html.erb" do
+ it "shoes outcome creation links if authorized" do
+ course = build_stubbed(:course, department: build_stubbed(:department))
+ stub_policy(create_outcomes?: true)
+
+ render "courses/interstitial", course: course
+
+ expect(page).to have_link "Adopt Default Outcomes"
+ end
+
+ it "does not show outcome creation links if unauthorized" do
+ course = build_stubbed(:course, department: build_stubbed(:department))
+ stub_policy(create_outcomes?: false)
+
+ render "courses/interstitial", course: course
+
+ expect(page).not_to have_link "Adopt Default Outcomes"
+ end
+end
@@ -0,0 +1,39 @@
+require "rails_helper"
+
+describe "courses/outcomes" do
+ it "shows the add assessment link if authorized" do
+ outcome = create(:outcome)
+ stub_policy(create_assessments?: true)
+
+ render "courses/outcomes", course: outcome.course
+
+ expect(page).to have_link("Add new assessment")
+ end
+
+ it "does not show the add assessment link if unauthorized" do
+ outcome = create(:outcome)
+ stub_policy(create_assessments?: false)
+
+ render "courses/outcomes", course: outcome.course
+
+ expect(page).not_to have_link("Add new assessment")
+ end
+
+ it "shows the create_custom outcomes link if authorized" do
+ course = build_stubbed(:course, has_custom_outcomes: true)
+ stub_policy(create_outcomes?: true)
+
+ render "courses/outcomes", course: course, unassociated_outcomes: []
+
+ expect(page).to have_link("New custom outcome")
+ end
+
+ it "does not show the create_custom outcomes link if unauthorized" do
+ course = build_stubbed(:course, has_custom_outcomes: true)
+ stub_policy(create_outcomes?: false)
+
+ render "courses/outcomes", course: course, unassociated_outcomes: []
+
+ expect(page).not_to have_link("New custom outcome")
+ end
+end

0 comments on commit 7443270

Please sign in to comment.