I have a Rails 7.1.3 app that has ActiveStorage and Ransack installed. I have a model called Upload
that has_one_attached :file
. I would like to search by filename, using Ransack, in the uploads/index
view. I have tried the answers here and the suggestion here, but neither are working. I have also tried to create lib/active_storage/attachment.rb
and add the rasackable_attributes
, but still no luck. The error I'm getting is Association named 'file' was not found on Upload; perhaps you misspelled it?
. Anyone have any idea how to get this to work?
Here is my code:
# upload.rb
has_one_attached :file
def self.ransackable_associations(auth_object = nil)
["file"]
end
# lib/active_storage/attachment.rb
class ActiveStorage::Attachment < ApplicationRecord
def self.ransackable_attributes(auth_object = nil)
["blob_id", "created_at", "id", "id_value", "name", "record_id", "record_type"]
end
end
/uploads/index.html.erb
<%= f.search_field :file_filename_cont, autofocus: true, placeholder: "Search by filename" %>
# controllers/uploads_controller.rb
@q = Upload.ransack(params[:q])
@uploads = @q.result.includes(:file)
has_one_attached :file
creates file_attachment
and file_blob
associations:
https://github.com/rails/rails/blob/v7.1.3.3/activestorage/lib/active_storage/attached/model.rb#L114-L115
you can use reflections to inspect associations:
>> Import.reflections.keys
=> ["file_attachment", "file_blob"]
ActiveStorage::Blob
is where the actual filename is stored:
>> ActiveStorage::Blob
=> ActiveStorage::Blob(id: integer, key: string, filename: string, content_type: string, metadata: text, service_name: string, byte_size: integer, checksum: string, created_at: datetime)
# ^^^^^^^^^^^^^^^^
Bring it all together:
# config/initializers/active_storage.rb
ActiveSupport.on_load(:active_storage_blob) do
def self.ransackable_attributes(auth_object = nil)
%w[filename]
end
end
# app/models/import.rb
class Import < ApplicationRecord
has_one_attached :file
def self.ransackable_attributes(auth_object = nil)
[]
end
def self.ransackable_associations(auth_object = nil)
["file_blob"]
end
end
# app/controllers/imports_controller.rb
class ImportsController < ApplicationController
# GET /imports
def index
@q = Import.ransack(params[:q])
@imports = @q.result
end
end
# app/views/imports/index.html.erb
<%= search_form_for @q do |f| %>
<%= f.label :file_blob_filename_cont %>
<%= f.search_field :file_blob_filename_cont %>
<% end %>
<%= render @imports %>
Seems to work:
>> Import.ransack({"file_blob_filename_cont"=>"ava"}).result
=> [#<Import:0x00007f9101d16048 id: 1>]
>> Import.ransack({"file_blob_filename_cont"=>"asdf"}).result
=> []