从Rails ActiveRecord集合中过滤结果

时间:2018-12-03 17:25:22

标签: ruby-on-rails ruby-on-rails-4

如何过滤活动记录集合返回的结果?我不是试图从“文章”表中删除,而是尝试根据每个文章的权限来筛选每个用户的结果。

我相信我可以使用where子句@articles.where(some condition),但是我必须检查每篇文章的privacy_level并根据不同的隐私级别应用其他过滤器,因此我不确定是否可行。

          @articles = Article.includes(:user, :country, :favorites)
                          .where(is_deleted: false)
                          .where("articles.organization_id is null OR articles.organization_id = #{@authenticated_user.organization.id}")
                          .filter(filter_items)
                          .order(sort_column + " " + sort_direction)
                          .paginate(page: params[:page])


          @articles.each do |article|

            if article.privacy_level == 0 and article.user_id != @authenticated_user.id
              # @articles.delete_at(article.id)
            end

            if article.privacy_level == 1 and article.organization_id != @authenticated_user.organization.id
               # remove from results
            end
          end

2 个答案:

答案 0 :(得分:3)

控制器中有很多逻辑要处理。我建议添加到您的文章模型中:

class Article < ApplicationRecord
  def self.articles_for_list(authenticated_user)
    where(privacy_level: 0).where.not(user_id: authenticated_user.id).or(
      where(privacy_level: 1).where.not(organization_id: authenticated_user.organization.id)
    )
  end
end

我认为这就是您要将它们添加到列表中的方式,但是我不确定。然后在您的控制器中:

@articles = Article.includes(:user, :country, :favorites)
                          .articles_for_list(@authenticated_user)
                          .where(is_deleted: false)
                          .where("articles.organization_id is null OR articles.organization_id = #{@authenticated_user.organization.id}")
                          .filter(filter_items)
                          .order(sort_column + " " + sort_direction)
                          .paginate(page: params[:page])

编辑:

适用于Rails 3+的Uglier版本:

class Article < ApplicationRecord
  def self.articles_for_list(authenticated_user)
    ids_1 = where(privacy_level: 0).where.not(user_id: authenticated_user.id).collect(&:id)
    ids_2 = where(privacy_level: 1).where.not(organization_id: authenticated_user.organization.id).collect(&:id)
    where(id: (ids_1 + ids_2))
  end
end

答案 1 :(得分:1)

您已经有这个人过滤您的文章:

.where("articles.organization_id is null OR articles.organization_id = #{@authenticated_user.organization.id}")

它应该已经在您的第一个条件下过滤掉了文章(它过滤掉了organization_id与通过身份验证的用户的组织不匹配的所有文章):

article.privacy_level == 0 and article.user_id != @authenticated_user.id

因此,您可以为第二个if条件向活动记录查询添加另一个where子句:

.where('article.privacy_level != 0 or article.user_id == ?', @authenticated_user.id)

附带说明:通常,您不想在SQL查询字符串中使用字符串插值,因为这样会使您容易受到SQL注入攻击的影响。

因此,您可能希望将第一个where更改为以下内容:

.where("articles.organization_id is null OR articles.organization_id = ?", @authenticated_user.organization.id)

查看rails security guide以获得更多详细信息。