什么是常见的做法范围记录是由那些在用户可以与QUOT;读"? [英] What is a common approach to scope records by those that an user can "read"?

查看:160
本文介绍了什么是常见的做法范围记录是由那些在用户可以与QUOT;读"?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用on Rails的3.2.2 Ruby和我想知道是什么时候,如果一个用户有适当的权限为读取的记载present在记录一个清单必须检查的常用方法。也就是在这个时候,我有以下几点:

I am using Ruby on Rails 3.2.2 and I would like to know what is a common approach when it must be checked if an user has proper authorizations to "read" records present in a "list" of records. That is, at this time I have the following:

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

通过使用上述code,我可以在执行授权检查一个的的文章对象:

@article.readable_by_user?(@current_user)

然而,当我想使(通常,在我的控制器首页动作)有点像通过检索恰好10个对象以下

However, when I would like to make (usually, in my controller index action) something like the following by retrieving exactly 10 objects

Article.readable_by_user(@current_user).search(...).paginate(..., :per_page => 10)

我还必须对每个对象执行授权检查。因此, 我可以对记录文章数组对象名单执行授权检查)的在智能/高性能的方式?也就是说,例如,要我打开 Article.all (也许订货那些创建的数据,限制了SQL查询到10条记录,...),然后在每个这些对象所以遍历执行授权检查?或者我应该做不同的东西(也许有一些SQL查询伎俩,一些Ruby on Rails的设施或别的什么)?

I must still to perform authorization checks on each object. So, what I can make to perform authorization checks on that "list" of records (an array of Article objects) in a "smart" / "performant" way? That is, for example, should I load Article.all (maybe ordering those by created data, limiting the SQL query to 10 records, ...) and then to iterate on each of those objects so to perform authorization checks? or should I make something different (maybe with some SQL query trick, some Ruby on Rails facility or something else)?

我试图通过用户手动使用的读的,例如=htt​​p://apidock.com/rails/ActiveRecord/Batches/find_each相对=nofollow的> find_each 方式:

I tried to retrieve articles readable by an user "manually", for example by using the find_each method:

# 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

在这个时候,上面的code是最高性能妥协,我能想到的,即使它有一些缺陷:它的限制的检索对象的量记录给定的量与给定的标识秒(10个记录默认在上面的例子中);实际上来说,是真的不通过用户检索可读的所有对象的,当你试图进一步范围,因为相关的的ActiveRecord ::关联 这里的/与对 readable_by_user 范围方法时(例如,​​当你也会由标题搜索文章添加更多的SQL查询语句),它会的限制的记录,那些其中(articles.id IN(?),readable_article_ids) (也就是说,它限制/限制检索和阅读对象的量前10和所有其他物品的的用户通过搜索时会被忽略标题)。为了使 readable_by_user 方法来正确地与更大范围的方法努力解决这一问题,可以做的没有突破块,以便加载所有的的文章,但没有良好的性能的原因时,有很多的记录(也许,另一种解决方案可能是存放在某处所有文章 ID 取值可读的用户,但我认为这不是一个普通/简单的解决方案,以解决这一问题)。

At this time, the above code is the most "performant compromise" that I can think of, even if it has some pitfall: it "restricts" the amount of retrieved objects to a given amount of records with given ids (10 records by default in the above example); practically speaking, it "really" doesn't retrieve all objects readable by an user since when you try to further scope the related ActiveRecord::Relation "where" / "with which" the readable_by_user scope method is used (for example, when you would also search articles by title adding a further SQL query clause), it would restrict records to those where("articles.id IN (?)", readable_article_ids) (that is, it "limits" / "restricts" the amount of retrieved and readable objects to first 10 and all others articles readable by the user will be ignored when searching by title). A solution to the issue in order to make the readable_by_user method to properly work with further scope methods could be to do not break the block so to load all readable articles, but it is no good for performance reasons when there are a lot of records (maybe, another solution could be to store somewhere all article ids readable by an user, but I think it is not a common/easy solution to solve the issue).

因此​​, 有某种方式来完成我想使高性能和真正的正确的方法(可能通过改变上述方法的话)?

So, there is some way to accomplish what I would like to make in a performant and "really" correct way (maybe, by changing the above approach at all)?

推荐答案

这取决于你的 readable_by_user 功能。如果很容易转化为一个SQL,比它前进的方向。如果是比这更复杂,那么你极有可能不得不手工做检查。

It depends on your readable_by_user function. If it is easy to translate into an SQL, than it is the way forward. If it is more complicated than that then you most probably have to do the check manually.

更新: 为了澄清创造可读名单我present一个例子SQL查询的地步。 假设,将物品以一给定用户的可读性是依赖于下列的:

UPDATE: To clarify the point of creating an SQL query for the readable list I present an example. Assume, that a readability of an article to a given user is dependent of the following:

  • 在用户自己的文章( SELECT a.user ==?从文章的一个WHERE a.id =?
  • 的文章是对所有人开放(选择a.state == 0从文章的一个WHERE a.user =?
  • 的用户是一组的访问文章成员
  • The user's own article (SELECT a.user == ? FROM Articles a WHERE a.id = ?)
  • The article is open to everyone (SELECT a.state == 0 FROM Articles a WHERE a.user = ?)
  • The user is member of a group with access to articles

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 = ?
    

    这些可以归纳为以下查询:

    These can be summarized in the following query:

    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查询。

    This is sure a complicated query, but the most efficient solution. The database should do database stuff, if you only use SQL queries and some logic to evaluate your readable_bu_user then you can translate it into one pure SQL query.

    这篇关于什么是常见的做法范围记录是由那些在用户可以与QUOT;读&QUOT;?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆