gpt4 book ai didi

ruby-on-rails - 用户可以 "read"范围记录的常用方法是什么?

转载 作者:行者123 更新时间:2023-12-04 18:19:01 27 4
gpt4 key购买 nike

我正在使用 Ruby on Rails 3.2.2,我想知道当必须检查用户是否具有“读取”记录“列表”中存在的记录的适当授权时,什么是常用方法。也就是说,此时我有以下内容:

class Article < ActiveRecord::Base
def readable_by_user?(user)
# Implementation of multiple authorization checks that are not easy to
# translate into an SQL query (at database level, it executes a bunch of
# "separate" / "different" SQL queries).

... # return 'true' or 'false'
end
end

通过使用上面的代码,我可以对单个文章对象执行授权检查:
@article.readable_by_user?(@current_user)

但是,当我想(通常在我的 Controller 中 index 操作)通过准确检索 10 个对象来执行以下操作时
Article.readable_by_user(@current_user).search(...).paginate(..., :per_page => 10)

我仍然必须对每个对象执行授权检查。所以, 我可以做什么来对记录的“列表”执行授权检查 ( Article 个对象的数组) 以“智能”/“高性能”的方式? 也就是说,例如,我应该加载 Article.all (也许通过创建的数据对它们进行排序,将 SQL 查询限制为 10 条记录,...)然后迭代每个对象以执行授权检查?还是我应该做一些不同的事情(也许使用一些 SQL 查询技巧、一些 Ruby on Rails 工具或其他东西)?

@Matzi 回答后更新

我试图“手动”检索用户可读的文章,例如使用 find_each 方法:
# Note: This method is intended to be used as a "scope" method
#
# Article.readable_by_user(@current_user).search(...).paginate(..., :per_page => 10)
#
def self.readable_by_user(user, n = 10)
readable_article_ids = []

Article.find_each(:batch_size => 1000) do |article|
readable_article_ids << article.id if article.readable_by_user?(user)

# Breaks the block when 10 articles have passed the readable authorization
# check.
break if readable_article_ids.size == n
end

where("articles.id IN (?)", readable_article_ids)
end

此时,上面的代码是我能想到的最“性能妥协”,即使它有一些陷阱:它将检索到的对象的数量“限制”为给定的记录数量,给定 id。 s(上例默认10条记录);实际上,它“真的”不会检索用户可读的所有对象,因为当您尝试进一步确定相关 ActiveRecord::Relation 的范围时 readable_by_user“在哪里”/“与哪个”使用 scope 方法(例如,当您还通过 title 添加进一步的 SQL 查询子句搜索文章时),它将限制记录到那些 where("articles.id IN (?)", readable_article_ids) (也就是说,它“限制”/“限制”检索和可读对象的数量为前 10 个,并且在搜索时将忽略用户可读的所有其他文章 title )。该问题的解决方案以使 readable_by_user正确使用其他范围方法的方法可能是不 break加载所有可读文章的 block ,但是当有很多记录时,出于性能原因,它是没有好处的(也许,另一种解决方案可能是将所有文章 id 存储在某处用户可读,但我认为它是不是解决问题的常见/简单的解决方案)。

所以, 有什么方法可以以一种高效且“真正”正确的方式完成我想做的事情(也许,通过改变上述方法)?

最佳答案

这取决于您的 readable_by_user功能。如果它很容易翻译成 SQL,那么它就是前进的方向。如果它比这更复杂,那么您很可能必须手动进行检查。

更新:
为了阐明为可读列表创建 SQL 查询的意义,我举了一个例子。
假设文章对给定用户的可读性取决于以下因素:

  • 用户自己的文章(SELECT a.user == ? FROM Articles a WHERE a.id = ?)
  • 文章对所有人开放(SELECT a.state == 0 FROM Articles a WHERE a.user = ?)
  • 用户是有权访问文章
  • 的组的成员

    sql:
    SELECT max(g.rights) > 64
    FROM Groups g
    JOIN Groups_users gu on g.id = ug.group_id
    WHERE gu.id = ?
  • 用户被分配给给定的文章

  • sql:
    SELECT 1
    FROM Articles_users au
    WHERE au.article_id = ? AND au.user_id = ?

    这些可以总结在以下查询中:
    def articles_for_user(user) 
    Articles.find_by_sql(["
    SELECT a.*
    FROM Articles a
    LEFT OUTER JOIN Articles_users au on au.article_id = a.id and au.user_id = ?
    WHERE a.user_id = ?
    OR au.user_id = ?
    OR 64 <= (SELECT max(g.rights)
    FROM Groups g
    JOIN Groups_users gu on g.id = ug.group_id
    WHERE gu.id = ?)
    ", user.id, user.id, user.id, user.id])
    end

    这肯定是一个复杂的查询,但却是最有效的解决方案。如果你只使用 SQL 查询和一些逻辑来评估你的 readable_bu_user,那么数据库应该做数据库的事情。然后您可以将其转换为一个纯 SQL 查询。

    关于ruby-on-rails - 用户可以 "read"范围记录的常用方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11074008/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com