问题描述
我在Rails 6应用程序中使用Devise和Active Storage。当前使用before_action: authenticate_user!
会为非用户禁用所有图像,这很不错,除了我希望允许record_type
中带有active_storage_attachments
'News'的图像可供用户和非用户查看。
下面的代码是我到目前为止的内容,查看了record_type
是新闻的ActiveStorage :: Attachment。此代码显示用户和非用户的所有图像,这是不理想的。
class ActiveStorage::BaseController < ActionController::Base
before_action :allow_certain_assets
include ActiveStorage::SetCurrent
protect_from_forgery with: :exception
private
def allow_certain_assets
if (ActiveStorage::Attachment.where(record_type: 'News')).present?
else
authenticate_user!
end
end
end
解决方法
您的代码存在的问题是您正在执行以下操作:
(ActiveStorage::Attachment.where(record_type: 'News')).present?
它将检查整个数据库,如果有attachment
为“新闻”的record_type
。但是相反,您需要检查用户尝试访问的特定图像是否为“新闻”类型,然后允许他使用,否则不允许他使用。一种方法是在可以检查的表演动作上:
def show
# this code might be incorrect and I am not sure how you would be getting
# the attachment object but this would explain a way you can authenticate it
@attachment = ActiveStorage::Attachment.find params[:id]
authenticate_user! unless @attachment.record_type == 'News'
end
因此,这将检查用户尝试访问的特定对象。
添加:
可以使用某些授权库自动完成这种类型的授权,例如:
您还可以在其中允许访客用户使用某些类型的图像,而仅允许注册用户使用其他类型的图像。
,这将与Pundit gem(@Deep here提到的选项之一)一起使用
# controller
class ImagesController < ApplicationController
def index
authorize :image,:index?
@images = policy_scope(ActiveRecord::Attachment)
end
def show
@image = policy_scope(ActiveRecord::Attachment).find(params[:id])
authorize @image,policy_class: ImagePolicy
end
end
# policy
class ImagePolicy < ApplicationPolicy
def index?
true # must be true so that every can see the list
end
def show?
true # optional: add more logic here
end
class Scope
def initialize(user,scope)
@user = user
@scope = scope
end
def resolve
if user
scope
else
scope.where(record_type: 'News') # we limit the records here
end
end
end
end