Given the following relations:
class User
has_many :messages
end
class Message
has_many_attached :files
end
I want to get the attachment by id, scoped on the current_user
. A way to do this is as follows:
current_user.messages.joins(:files_attachments).where(active_storage_attachments: { blob_id: params[:id] }).first.files.find(params[:id])
I was wondering if there was a prettier way that's still efficient?
The main issue is that record
is polymorphic, so this gives an error:
ActiveStorage::Attachment.includes(:record).where(messages: { user_id: current_user.id }).find_by(blob_id: params[:id] })
Users can have many messages, so this solution would be too inefficient:
ActiveStorage::Attachment.where(record_type: "Message", record_id: current_user.messages.pluck(:id)).find_by(blob_id: params[:id] })
To get an attachment by its id - blob_id
scoped to only the current user (addressing security concerns), define a scope in the User model:
class User
has_many :messages
def find_attachment_by_blob_id(blob_id)
ActiveStorage::Attachment
.joins("INNER JOIN messages ON messages.id = active_storage_attachments.record_id AND active_storage_attachments.record_type = 'Message'")
.where(messages: { user_id: id })
.find_by(active_storage_attachments: { blob_id: blob_id })
end
end
Then you can get the attachment by:
attachment = current_user.find_attachment_by_blob_id(params[:id])