为什么declarative_authorization会破坏我的控制器的功能? - Rails 3

时间:2011-08-26 06:30:31

标签: ruby-on-rails ruby-on-rails-3 declarative-authorization

我有一个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。所以过滤器部分工作。

5 个答案:

答案 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

这会保留对其他控制器操作的权限检查以及“生成”操作,但会从自动查找程序查找中免除“生成”方法。

有关详细信息,请参阅: http://rubydoc.info/github/stffn/declarative_authorization/master/Authorization/AuthorizationInController/ClassMethods

答案 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来电的成功与否,因此如果出现错误,您就不会知道。