Reputation: 65
I am attempting to use the trix/actiontext feature of rails 7 to upload images to be included in my blog. I am planning to store them in AWS-S3 bucket, but the problem also happens when trying to store on local disk. Trix works normally when just doing text content with no errors. When I click the "paperclip" icon to attach a file, I get prompted to select a file, and it appears that I am able to, however, there are errors in the console and when I click submit, the file does not save. This is the error in the console as soon as I choose an image to attach:
POST http://localhost:3000/rails/active_storage/direct_uploads 422 (Unprocessable Entity) actiontext.js:543
Uncaught Error: Direct upload failed: Error creating Blob for "Screenshot from 2022-10-13 12-38-57.png". Status: 422 at AttachmentUpload.directUploadDidComplete (actiontext.js:849:13) at BlobRecord2.callback (actiontext.js:618:13) at BlobRecord2.requestDidError (actiontext.js:560:12) at BlobRecord2.requestDidLoad (actiontext.js:556:14) at XMLHttpRequest. (actiontext.js:527:56)
Here is the error from the rails server:
Started POST "/rails/active_storage/direct_uploads" for ::1 at 2022-11-03 14:20:10 -0500 14:20:10 web.1 | Processing by ActiveStorage::DirectUploadsController#create as JSON 14:20:10 web.1 | Parameters: {"blob"=>{"filename"=>"Screenshot from 2022-10-26 15-49-39.png", "content_type"=>"image/png", "byte_size"=>336871, "checksum"=>"TZneH7Z7DdCSftEvona6zg=="}, "direct_upload"=>{"blob"=>{"filename"=>"Screenshot from 2022-10-26 15-49-39.png", "content_type"=>"image/png", "byte_size"=>336871, "checksum"=>"TZneH7Z7DdCSftEvona6zg=="}}} 14:20:10 web.1
Completed 422 Unprocessable Entity in 33ms (ActiveRecord: 8.4ms | Allocations: 14851)
ActiveRecord::RecordInvalid (Validation failed: Service name can't be blank): 14:20:10
There is of course a much longer stack trace, but that appears to be the important part. I'm happy to provide the rest if anyone wants it.
When I click submit on the form, I get my normal toast message saying blog is successfully updated, but the image file is not added to the post. I've been searching for the answer to this problem for 3 days and I'm starting to go around in circles. I know that service_name is a column in the actives_storage_blobs database table, but I don't know where it pulls service name from or how to get it there. I'm thinking it's from the service in storage.yml, and it is present there.
storage.yml:
local:
service: Disk
root: <%= Rails.root.join("storage") %>
I'm running out of things to try and search for this problem. I have disabled turbo for the blogs page as I had found a github discussion relating to that, but it hasn't helped. I have read through the guides for active storage and action text multiple times and have not found anything that helped. I would greatly appreciate any suggestions. Thank you.
In case it helps:
Here is the relevant part of the form at app/views/blogs/_form.html.erb:
<div class="form-group">
<%= form.rich_text_area :body, class: 'form-control', rows: 15, placeholder: 'Content' %>
</div>
app/controllers/blogs_controller.rb:
class BlogsController < CommentsController
before_action :set_blog, only: %i[ show edit update destroy toggle_status ]
before_action :set_sidebar_topics, except: [:update, :create, :destroy, :toggle_status]
layout "blog"
access all: [:show, :index], user: { except: [:destroy, :new, :create, :update, :edit, :toggle_status] }, admin: :all, testing: { except: [:destroy, :create, :update]}
def index
if logged_in?(:admin) || logged_in?(:testing)
@blogs = Blog.recent.with_rich_text_body_and_embeds.page(params[:page]).per(5)
else
@blogs = Blog.published.recent.with_rich_text_body_and_embeds.page(params[:page]).per(5)
end
@page_title = "My Portfolio Blog"
end
def show
if logged_in?(:admin) || logged_in?(:testing) || @blog.published?
@blog = Blog.includes(:comments).friendly.find(params[:id])
@comment = Comment.new
@page_title = @blog.title
@seo_keywords = @blog.body
else redirect_to blogs_path, notice: 'You are not authorized to access this page.'
end
end
def new
@blog = Blog.new
end
def edit
end
def create
@blog = Blog.new(blog_params)
respond_to do |format|
if @blog.save
format.html { redirect_to blog_url(@blog), success: "Blog was successfully created." }
else
flash[:danger] = "Blog must have title, body and topic."
format.html { render :new, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if @blog.update(blog_params)
format.html { redirect_to blog_url(@blog), success: "Blog was successfully updated." }
else
format.html { render :edit, status: :unprocessable_entity }
end
end
end
def destroy
@blog.destroy
respond_to do |format|
format.html { redirect_to blogs_url, status: :see_other }
end
end
def toggle_status
if @blog.draft? && logged_in?(:admin)
@blog.published!
elsif @blog.published? && logged_in?(:admin)
@blog.draft!
end
redirect_to blogs_url, success: 'Post status has been updated.'
end
private
def set_blog
@blog = Blog.friendly.find(params[:id])
end
def blog_params
params.require(:blog).permit(:title, :body, :topic_id, :status, images: [])
end
def set_sidebar_topics
@side_bar_topics = Topic.with_blogs
end
end
app/models/blog.rb:
class Blog < ApplicationRecord
enum status: { draft: 0, published: 1 }
extend FriendlyId
friendly_id :title, use: :slugged
validates_presence_of :title, :body, :topic_id
has_rich_text :body
has_many_attached :images, dependent: :destroy
has_many :comments, as: :commentable, dependent: :destroy, counter_cache: :commentable_count
belongs_to :topic, optional: true
def self.special_blogs
all
end
def self.featured_blogs
limit(2)
end
def self.recent
order("updated_at DESC")
end
end
ActiveRecord::Schema[7.0].define(version: 2022_10_14_225319) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "action_text_rich_texts", force: :cascade do |t|
t.string "name", null: false
t.text "body"
t.string "record_type", null: false
t.bigint "record_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["record_type", "record_id", "name"], name: "index_action_text_rich_texts_uniqueness", unique: true
end
create_table "active_storage_attachments", force: :cascade do |t|
t.string "name", null: false
t.string "record_type", null: false
t.bigint "record_id", null: false
t.bigint "blob_id", null: false
t.datetime "created_at", null: false
t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
end
create_table "active_storage_blobs", force: :cascade do |t|
t.string "key", null: false
t.string "filename", null: false
t.string "content_type"
t.text "metadata"
t.string "service_name", null: false
t.bigint "byte_size", null: false
t.string "checksum"
t.datetime "created_at", null: false
t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
end
create_table "active_storage_variant_records", force: :cascade do |t|
t.bigint "blob_id", null: false
t.string "variation_digest", null: false
t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true
end
create_table "blogs", force: :cascade do |t|
t.string "title"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "slug"
t.integer "status", default: 0
t.bigint "topic_id"
t.integer "commentable_count"
t.text "body"
t.index ["slug"], name: "index_blogs_on_slug", unique: true
t.index ["topic_id"], name: "index_blogs_on_topic_id"
end
create_table "comments", force: :cascade do |t|
t.bigint "user_id", null: false
t.string "commentable_type", null: false
t.bigint "commentable_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "body"
t.index ["commentable_type", "commentable_id"], name: "index_comments_on_commentable"
t.index ["user_id"], name: "index_comments_on_user_id"
end
create_table "friendly_id_slugs", force: :cascade do |t|
t.string "slug", null: false
t.integer "sluggable_id", null: false
t.string "sluggable_type", limit: 50
t.string "scope"
t.datetime "created_at"
t.index ["slug", "sluggable_type", "scope"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type_and_scope", unique: true
t.index ["slug", "sluggable_type"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type"
t.index ["sluggable_type", "sluggable_id"], name: "index_friendly_id_slugs_on_sluggable_type_and_sluggable_id"
end
create_table "portfolios", force: :cascade do |t|
t.string "title"
t.string "subtitle"
t.text "body"
t.text "main_image"
t.text "thumb_image"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "position"
end
create_table "skills", force: :cascade do |t|
t.string "title"
t.integer "percent_utilized"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "badge"
end
create_table "technologies", force: :cascade do |t|
t.string "name"
t.bigint "portfolio_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["portfolio_id"], name: "index_technologies_on_portfolio_id"
end
create_table "topics", force: :cascade do |t|
t.string "title"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "name"
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "roles"
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
add_foreign_key "blogs", "topics"
add_foreign_key "comments", "users"
add_foreign_key "technologies", "portfolios"
end
Upvotes: 1
Views: 1432
Reputation: 65
I am going to stop this question. It appears that rails needed updating. I did rails app:update and there were updates related to actiontext and activestorage and the DB schema was updated for those 3 relevant tables. I have done an upload through action text and it has worked. It's not displaying properly but there is data in my storage folder. I am going to go through everything as it is now to see if I can get the image to display properly and will ask a new question if needed. Thank you very much for helping.
Edit to add: Updating rails did fix the uploads completely. The update changed the image processor from mini-magick to vips. Adding this line to application.rb switched it back and then everything worked properly.
config.active_storage.variant_processor = :mini_magick
Upvotes: 5