检查数组中每条记录的康康康能力是否正确?

Is it correct to check cancancan abilities for each record in array?

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

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

更新:添加 ability.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

能力本身不存储在数据库中。这是一个 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',当然,您已经获取了很多文章。

如果你cancan的能力是,例如:

  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

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

无论在什么情况下,都无法避免向每篇文章询问权限,当然,除非您只加载用户可以加载的文章 'like',那么就没有必要询问 ;)。

编辑:

让我们检查一下您的 ability.rb

if user.admin?
  can :manage, :all

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

然而,exists?查询数据库,它搜索一个喜欢的关联用户和文章。

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

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

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