I have a Coupons
controller with two actions.
class CouponsController < ApplicationController
filter_resource_access
def index
@coupons = Coupon.all
end
#generates 10 new coupons on each call
def generate
plan_id = params[:plan_id]
numdays = params[:num_days]
(1..10).each do |i|
validChars = %w{ 1 2 3 4 5 6 7 9 a A b B d D e E f g G h H j J k K m M n N p P q Q r R t T }.to_a
code = (0...6).map{ validChars[ rand(validChars.size) ] }.join
coupon = Coupon.new
coupon.code = code
coupon.plan_id = plan_id
coupon.active = false
coupon.subdays = numdays
coupon.save
end
redirect_to :coupons_path
end
end
The generate action is invoked in my view like this:
<h2 class="page-title">Coupons</h2>
<div class="main">
<%= form_tag "coupons/generate" do -%>
<%= hidden_field_tag 'user[plan_id]', "1" %>
<%= hidden_field_tag 'user[num_days]', "150" %>
<%= submit_tag "Generate 10 Coupons!", :class => "primary button" %>
<% end -%>
<table border="0" class="list">
<thead>
<tr>
<th>Code</th><th>Plan</th><th>Duration</th><th>Activated</th>
</tr>
</thead>
<tbody>
<% if !@coupons.nil? %>
<% @coupons.each do |coupon| %>
<tr class="<%#= list_entry or list_entry_alt %>">
<td><%= coupon.code %></td>
<td><%= coupon.plan_id %&开发者_开发技巧gt;</td>
<td><%= coupon.subdays %> days</td>
<td><% if coupon.started.nil? == true %>
<%= 'Not yet' %>
<% else %>
<%= time_ago_or_time_stamp coupon.started %>
<% end %>
</td>
</tr>
<% end %>
<% end %>
</tbody>
</table>
</div>
My config/authorization_rules.rb
looks like this:
has_permission_on [:coupons], :to => [:index, :show, :step, :new, :create, :edit, :update, :destroy, :generate]
The error all of the above throws is this:
filter_access_to tried to find Coupon from params[:id] (nil), because attribute_check is enabled and @coupon isn't set, but failed: ActiveRecord::RecordNotFound: Couldn't find Coupon without an ID
Completed 404 Not Found in 245ms
ActiveRecord::RecordNotFound (Couldn't find Coupon without an ID):
However, once I change the filter_resource_access
to filter_access_to :all, :except => :generate
it doesn't give me the error anymore and kinda works.
i.e. it produces some of the coupon codes that I am looking for, but it doesn't include the plan_id number or the number of days in the output in the view.
Why is that? What am I doing wrong?
Edit 1: By the way, it does restrict the right people...i.e. only the specified roles can view the coupons index view
. So the filter partly works.
filter_resource_access triggers the declarative auth framework to perform a lookup on the :id parameter for your resource (in non- collection/creator methods).
In your example, it would do a @coupon = Coupon.find(params[:id]) and set up that member variable for your controller. However, since there is no params[:id] coming in to that action through that route, it fails.
The way around it, while still preserving your controller permissions is pretty easy. Just put this at the top of your controller on the filter_resource_access line:
filter_resource_access :additional_collection => { :generate => :read }
# I tried the two lines below but to no avail
#filter_resource_access :additional_collection => { :generate => :read }, :no_attribute_check => [ :generate ]
# filter_access_to :generate, :attribute_check => false
This maintains your permission checks against the other controller actions as well as the "generate" action but exempts the "generate" method from an automatic finder lookup.
For more info see: http://rubydoc.info/github/stffn/declarative_authorization/master/Authorization/AuthorizationInController/ClassMethods
My guess is that filter_resource_access
is treating all the actions in the controller as if they're dealing with a single resource and attempting to do Coupon.find(params[:id])
. By changing it to this:
filter_access_to :all, :except => :generate
You are telling it to not run that method before that action, meaning it won't try to find a coupon.
The problem is that with filter_resource_access it assumes the controller uses default resource actions and tries to find a dealer if params[:id] for the actions that are not standard crud. What you need to do is to add
filter_access_to :all
And add the corresponding rule for :generate to your authorization_rules.rb. Like
role :someone do
has_permission_on :coupon, :to => :generate
...
end
Declarative Authorization needs you to declare coupon as an instance variable.
In your controller, try changing coupon = Coupon.new
to @coupon = Coupon.new
(Obviously change the subsequent lines accordingly.)
filter_resource_access tries to create the resource object for you, so you needs to look at the :additional_member
or :additional_collection
options, or use the except
option as you noted.
As for the missing plan parameters, are you sure they come in as params[:plan_id]
? check your devel logs to see what the incoming params look like.
You also aren't checking the success of the save
call, so if there is an error, you won't know it.
精彩评论