我有一个Coupons
控制器,有两个动作。
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
在我的视图中调用generate动作,如下所示:
<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 %></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>
我的config/authorization_rules.rb
看起来像这样:
has_permission_on [:coupons], :to => [:index, :show, :step, :new, :create, :edit, :update, :destroy, :generate]
以上所有抛出的错误都是:
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):
但是,一旦我将filter_resource_access
更改为filter_access_to :all, :except => :generate
,它就不会再给我错误了,并且有点工作。
即。它会生成我正在寻找的一些优惠券代码,但它不包括plan_id编号或视图中输出的天数。
为什么?我做错了什么?
编辑1:顺便说一下,它确实限制了合适的人......即。只有指定的角色才能查看coupons index view
。所以过滤器部分工作。
答案 0 :(得分:2)
filter_resource_access触发声明性auth框架,以对资源的:id参数执行查找(在非集合/创建者方法中)。
在您的示例中,它将执行@coupon = Coupon.find(params [:id])并为您的控制器设置该成员变量。但是,由于没有params [:id]通过该路由进入该操作,因此失败。
围绕它的方式,同时仍然保留您的控制器权限非常容易。只需将它放在filter_resource_access行的控制器顶部:
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
这会保留对其他控制器操作的权限检查以及“生成”操作,但会从自动查找程序查找中免除“生成”方法。
答案 1 :(得分:1)
我的猜测是filter_resource_access
正在处理控制器中的所有操作,就好像他们正在处理单个资源并尝试Coupon.find(params[:id])
一样。通过将其更改为:
filter_access_to :all, :except => :generate
您告诉它不在该操作之前运行该方法,这意味着它不会尝试查找优惠券。
答案 2 :(得分:1)
问题在于,使用filter_resource_access,它假定控制器使用默认资源操作,并尝试查找经销商,如果params [:id]用于非标准crud的操作。 你需要做的是添加
filter_access_to :all
并为您的authorization_rules.rb添加相应的规则:generate。 像
role :someone do
has_permission_on :coupon, :to => :generate
...
end
答案 3 :(得分:0)
声明性授权需要您将优惠券声明为实例变量。
在您的控制器中,尝试将coupon = Coupon.new
更改为@coupon = Coupon.new
(显然会相应地更改后续行。)
答案 4 :(得分:0)
filter_resource_access尝试为您创建资源对象,因此您需要查看:additional_member
或:additional_collection
选项,或使用您提到的except
选项。
至于缺少的计划参数,您确定它们是params[:plan_id]
吗?检查你的开发日志,看看传入的参数是什么样的。
您也没有检查save
来电的成功与否,因此如果出现错误,您就不会知道。