如何编写需要 N 个父资源之一存在的 RESTful 控制器?

发布于 2024-12-01 01:39:22 字数 929 浏览 0 评论 0原文

我们使用康康。在我们的图书馆应用程序中,可以签出BookMagazine

POST /books/123/loans      # LoansController#new :book_id     => 123
POST /magazines/456/loans  # LoansController#new :magazine_id => 456

BooksMagazine有一个父类< code>Stockable,所以上面等价于:

POST /stockables/123/loans  # LoansController#new :stockable_id => 123
POST /stockables/456/loans  # LoansController#new :stockable_id => 456

然而,并不是每个 Stockable 都可以借出:

# error: can't check out reference books from the library
POST /reference_books/789/loans # LoansController#new :reference_book_id => 789

# same error
POST /stockables/789/loans      # LoansController#new :stockable_id      => 789  

用 CanCan 编写 LoansController 的正确方法是什么,以便它可以处理任何事情可借,而不需要为所有可借制定特定路线?

We use CanCan. In our library application, a Book or Magazine can be checked out:

POST /books/123/loans      # LoansController#new :book_id     => 123
POST /magazines/456/loans  # LoansController#new :magazine_id => 456

Books and Magazines have a parent class Stockable, so the above is equivalent to:

POST /stockables/123/loans  # LoansController#new :stockable_id => 123
POST /stockables/456/loans  # LoansController#new :stockable_id => 456

However, not every Stockable can be loaned:

# error: can't check out reference books from the library
POST /reference_books/789/loans # LoansController#new :reference_book_id => 789

# same error
POST /stockables/789/loans      # LoansController#new :stockable_id      => 789  

What's the right way to write the LoansController with CanCan so that it can handle anything that's Loanable, without needing to make a specific route for everything that's Loanable?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

简美 2024-12-08 01:39:22

我只会使用ability.rb 来定义每种对象类型允许/不允许执行哪些操作。以下假设您使用的是 STI,因此有一个 stockable_type 列,其中包含每行在数据库中代表的类的名称。如果您不使用 STI,您仍然可以使用另一种方法来正确确定对象类型(可能通过将块传递给 cancannot 方法,而不是使用哈希语法[查看 CanCan wiki,定义能力了解更多信息])。

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new # guest user (not logged in)
    can [:read], :all
    can :new, Loan, :stockable_type => ["Book", "Magazine"]
    cannot :new, Loan, :stockable_type => "ReferenceBook"
  end
end

然后,只需在 LoansController 中捕获 CanCan::AccessDenied,您就可以重定向尝试签出参考书的人员。

rescue_from CanCan::AccessDenied do |exception|
  redirect_to some_url, :alert => "You can't check out reference books!"
end

I would just use ability.rb to define what actions are / are not allowed for each object type. The following is assuming you're using STI, and so there is a stockable_type column containing the name of the class each row represents in your db. If you aren't using STI you can still use another method to correctly determine object type (probably by passing a block to the can and cannot methods instead of using the hash syntax [check the CanCan wiki, Defining Abilities for more info]).

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new # guest user (not logged in)
    can [:read], :all
    can :new, Loan, :stockable_type => ["Book", "Magazine"]
    cannot :new, Loan, :stockable_type => "ReferenceBook"
  end
end

Then, just catch CanCan::AccessDenied in your LoansController and you can redirect people attempting to checkout reference books.

rescue_from CanCan::AccessDenied do |exception|
  redirect_to some_url, :alert => "You can't check out reference books!"
end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文