Search code examples
ruby-on-railsdevise

Rails 6, Devise and Active Storage


I'm using Devise and Active Storage in my rails 6 application. Currently using before_action: authenticate_user! disables all images for non users, which is great, except I want to allow images with the record_type 'News' in my active_storage_attachments to be viewable by users and non users.

The below code is what I have so far, looking at ActiveStorage::Attachment where the record_type is News. This code shows all images for both users and non users which is not ideal.

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

Solution

  • The issue with your code is you are doing this:

    (ActiveStorage::Attachment.where(record_type: 'News')).present?
    

    which will check the whole database if there is any attachment with record_type 'News'. But instead you need to check if the particular image the user is trying to access is of 'News' type then allow him or else don't allow him. One way to do this would be on the show action you can check:

    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
    

    So this will check the particular object the user is trying to access.

    Add on:

    This type of authorization can be done automatically using some authorization libraries like:

    1. CanCanCan
    2. Pundit

    where you can allow certain type of images for guest user too and the other type of images only for a registered user.