【问题标题】:Is it correct to check cancancan abilities for each record in array?检查数组中每条记录的cancancan能力是否正确?
【发布时间】:2017-03-30 18:27:02
【问题描述】:

从数据库的角度来看。 例如,我在页面(文章)上有 30 条记录,我想检查是否可以创建“Like”。因此,将对数据库进行 30 次查询来检查此功能。执行此类能力检查的最佳做法是什么?

<% @articles.each do |article| %>
  <% if can? :create, Like.new(user: user, article: article) %>
      <%= link_to "Like!", like_path(article) %>
  <% end %>
<% end %>

更新:添加能力.rb

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new
    if user.admin?
      can :manage, :all
    else
      can :create, Like do |like|
        !Like.exists?(user: user, article: like.article)
      end
    end
  end
end

【问题讨论】:

  • 请出示您的ability.rb文件
  • 我看不出在上面的 sn-p 中哪里会发生数据库查询?有没有其他代码可以做到这一点?

标签: ruby-on-rails ruby postgresql cancancan


【解决方案1】:

能力本身并不存储在数据库中。这是example

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new # guest user (not logged in)
    if user.admin?
      can :manage, :all
    else
      can :read, :all
    end
  end
end

如你所见,它并没有触及数据库,因为你已经有了一个用户变量,你需要做的就是询问一个属性。

在您的示例中,我假设您已经加载了一个“用户”,当然,您已经获取了很多文章。

如果可以的话,例如:

  user ||= User.new  
  can :manage, Article do |a|
      a.user_id== user.id
    end

那么就不会进行任何查询,因为您已经拥有一篇文章的所有信息。

但是,如果您必须加载额外的信息,例如

  can :manage, Article do |i|
      user.friends_articles.exists?(i.id)
    end

然后进行查询(您必须查看文章是否属于用户朋友的收藏)。

无论在哪种情况下,都必须向每篇文章询问权限,当然,除非您只加载用户可以“喜欢”的文章,那么就不需要询问;)。

编辑:

让我们检查你的能力.rb

if user.admin?
  can :manage, :all

User.admin?,假设是管理员?只是一个属性,那么它就已经被加载了,并且没有进行额外的查询。

但是,exists? 查询数据库,它会搜索类似关联的用户和文章。

  can :create, Like do |like|
    !Like.exists?(user: user, article: like.article)

正如我之前所说,没有办法避免这种情况,除非您在 @article 集合中进行一些操作。

我能想到的一个高级想法是在一个数据库事务中加载@articles_liked 和@articles_no_like,然后将它们混合显示,这需要一些工作。

【讨论】:

  • 感谢您的回答!我添加了ability.rb。
  • 谢谢你,加斯顿!我认为更好的方法是尽可能避免这种方法。
猜你喜欢
  • 1970-01-01
  • 2020-04-26
  • 1970-01-01
  • 1970-01-01
  • 2011-05-14
  • 2016-06-08
  • 2015-03-11
  • 2014-07-07
  • 1970-01-01
相关资源
最近更新 更多