Image upload component for Funicular.
The plugin only owns the browser-side interaction: file selection, object URL preview, optional FormData upload, and display of the current image URL. The Rails app owns persistence. The same component works with a controller that stores bytes in SQLite or one that attaches the upload to Active Storage.
group :funicular do
gem "funicular-image-uploader"
endRender plugin assets from the Rails layout:
<%= funicular_plugin_include_tags %>Use on_select when an image should be submitted together with other form
fields:
component(
Funicular::Plugins::ImageUploader::Component,
src: current_user.has_avatar ? "/users/#{current_user.id}/avatar" : nil,
input_id: "avatar-input",
file_field: "avatar",
image_class: "profile-avatar-image",
input_class: "profile-avatar-input",
on_select: ->(file, preview_url) { @selected_avatar_file = file }
)If no classes are supplied, the plugin's default CSS styles the file selector, clear button, and upload button. Applications can pass class props when they need to align the component with their own design system.
The parent component can then send its form data with
Funicular::FileUpload.upload_with_formdata.
Use auto_upload: true when the image has its own endpoint:
component(
Funicular::Plugins::ImageUploader::Component,
src: "/users/#{current_user.id}/avatar",
upload_url: "/users/#{current_user.id}/avatar",
file_field: "avatar",
auto_upload: true,
on_upload: ->(result) { puts "uploaded" },
on_error: ->(message, result) { puts message }
)The endpoint should return JSON. If it includes image_url, the component uses
that URL after upload. Override the key with response_url_key: "url".
class Users::AvatarsController < ApplicationController
before_action :require_login
def update
current_user.avatar.attach(params[:avatar])
render json: {
image_url: rails_blob_path(current_user.avatar, only_path: true)
}
end
endresource :avatar, only: [:update], controller: "users/avatars"For direct SQLite storage, read params[:avatar] in the controller and return
the URL that serves the stored bytes.