Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Embedding images in Trix editor does not work (app helpers not available in Avo) #2638

Closed
3 of 9 tasks
sedubois opened this issue Mar 26, 2024 · 15 comments · Fixed by #2639
Closed
3 of 9 tasks

Embedding images in Trix editor does not work (app helpers not available in Avo) #2638

sedubois opened this issue Mar 26, 2024 · 15 comments · Fixed by #2639

Comments

@sedubois
Copy link
Contributor

sedubois commented Mar 26, 2024

Describe the bug

Embedding images in Trix editor either leads to error or results in images which do not persist (see below).

Steps to Reproduce

Steps to reproduce the behavior:

  1. Create a resource with field :body, as: :trix
  2. Create a new record
  3. Go back to the edit page
  4. Click on the paperclip icon in the Trix toolbar for this field
  5. Select some image file

Expected behavior & Actual behavior

Expected: the image gets inserted. After saving, it renders correctly.

Actual: error You haven't set an attachment_key to this Trix field. But the documentation does not specify which value should be put for attachment_key. I tried embeds and trix_attachments, neither of those allow to embed images which persist after saving. Besides, Avo should be able to figure out by itself what is required: we have been able to embed images without specifying any "attachment key" when using Administrate.

Models and resource files

class Article < ApplicationRecord
  has_rich_text :body
end
class Avo::Resources::Article < Avo::BaseResource
  def fields
    field :body, as: :trix
  end
end

System configuration

Avo version: 3.5.5

Rails version: 7.0.8.1

Ruby version: 3.3.0

License type:

  • Community
  • Pro
  • Advanced

Impact

  • High impact (It makes my app un-usable.)
  • Medium impact (I'm annoyed, but I'll live.)
  • Low impact (It's really a tiny thing that I could live with.)

Urgency

  • High urgency (I can't continue development without it.)
  • Medium urgency (I found a workaround, but I'd love to have it fixed.)
  • Low urgency (It can wait. I just wanted you to know about it.)

The only workaround known to us currently is to stop Avo development and continue to rely on Administrate as far as these resources are concerned.

@Paul-Bob
Copy link
Contributor

Hello @sedubois maybe this documentation section helps to clear things out https://docs.avohq.io/3.0/fields/trix.html#file-attachments

The attachment_key should have the same name as the attachment association on your model:

If you have this model:

class Post < ApplicationRecord
  has_many_attached :trix_attachments
end

You should declare the field this way:

field :body, as: :trix, attachment_key: :trix_attachments

The attachment_key is the bridge between the field and the association that will keep the attachments.

@sedubois
Copy link
Contributor Author

Hi @Paul-Bob I saw that documentation, but what should I specify when my model just has:

class Article < ApplicationRecord
  has_rich_text :body
end

I tried this but doesn't work:

class Avo::Resources::Article < Avo::BaseResource
  def fields
    # also tried field :body, as: :trix, attachment_key: :embeds
    field :body, as: :trix, attachment_key: :trix_attachments
  end
end

@Paul-Bob
Copy link
Contributor

If you want to save several files you can do:

class Article < ApplicationRecord
  has_rich_text :body

  has_many_attached :the_attachments_name
end

Then:

class Avo::Resources::Article < Avo::BaseResource
  def fields
    field :body, as: :trix, attachment_key: :the_attachments_name
  end
end

@Paul-Bob
Copy link
Contributor

This behaviour is needed specially when using a text structure without has_rich_text, Avo needs to know where to attach the files. For has_rich_text it might be possible to ignore this option, we'll give it a look maybe we can remove the need of attachment_key when using rich text and also fix this one #2538

@sedubois
Copy link
Contributor Author

sedubois commented Mar 26, 2024

Thanks @Paul-Bob but my understanding it that it should just work with has_rich_text :body:
https://edgeguides.rubyonrails.org/action_text_overview.html#creating-rich-text-content

Our app has been working this way for many years, both the front-end where the posts are rendered, and the Administrate backend.

We need to keep compatibility for our existing records with rich text. We want to start to be able to edit them with Avo without losing existing embeds.

@Paul-Bob
Copy link
Contributor

@sedubois I understand your concern and we're working on it. Can you please follow this steps and return with feedback if this works or not?

  1. In avo.rb after config:
Avo.configure do |config|
  # ...
end

Rails.configuration.to_prepare do
  # ...
  Avo::BaseComponent.delegate :rich_text_area_tag, to: :helpers
end
  1. Run $ rails g avo:eject --field-components trix --view edit --scope active_text
  2. Replace the code on the ejected app/components/avo/fields/active_text/trix_field/edit_component.html.erb to:
<%= field_wrapper **field_wrapper_args do %>
  <%= @form.rich_text_area @field.id,
    value: @field.value,
    class: classes("w-full"),
    data: @field.get_html(:data, view: view, element: :input),
    disabled: disabled?,
    placeholder: @field.placeholder,
    style: @field.get_html(:style, view: view, element: :input)
  %>
<% end %>
  1. Use this configuration on the field:
    field : body, as: :trix, components: {
      edit_component: Avo::Fields::ActiveText::TrixField::EditComponent
    }

sedubois added a commit to sedubois/avo-debug that referenced this issue Mar 26, 2024
@sedubois
Copy link
Contributor Author

sedubois commented Mar 26, 2024

Thanks @Paul-Bob, I've applied the changes:
sedubois/avo-debug@8ba9f85

It seems to be an improvement as the embedded image gets saved to Active Storage.

However:

  1. on edit: the text formatting in the field is wrong, see images below
  2. on show (after I embed an image then click save), I get this error: Can't resolve image into URL: undefined method 'to_model' for an instance of ActiveStorage::VariantWithRecord. This is raised in app/views/active_storage/blobs/_blob.html.erb:3 which is a file which was created by rails g action_text:install.
Screenshot 2024-03-26 at 15 50 29 Screenshot 2024-03-26 at 15 50 53

@Paul-Bob
Copy link
Contributor

The show issue can be solved replacing some blob code into:

# Original
<% if blob.representable? %>
  <%= image_tag blob.representation(resize_to_limit: local_assigns[:in_gallery] ? [ 800, 600 ] : [ 1024, 768 ]) %>
<% end %>

# Replace with this
<% if blob.representable? %>
  <%= image_tag main_app.url_for(blob) %>
<% end %>

Thanks for confirming that’s working, you can use this as a workaround until we release a proper per fix or revert the changes until then

@sedubois
Copy link
Contributor Author

Thanks @Paul-Bob! That temporarily resolves point 2 👍

But:

  • in our real app, app/views/active_storage/blobs/_blob.html.erb calls not blob.representation but a custom helper method called responsive_image_tag which isn't found. How to make it available to the blob partial?
  • the issue 1 (broken layout) prevents from using these changes in prod

@adrianthedev
Copy link
Collaborator

@sedubois can you paste the contents of your app/views/active_storage/blobs/_blob.html.erb?
It seems very important that we know what that does.

@sedubois
Copy link
Contributor Author

@adrianthedev see below. The helper code is used both in the app front-end and in the existing Administrate dashboards. We would need to start using these in Avo as well.

<%# app/views/active_storage/blobs/_blob.html.erb %>

<% blob_html = capture do %>
  <figure class="attachment attachment--<%= blob.representable? ? "preview" : "file" %> attachment--<%= blob.filename.extension %>">
    <% if blob.representable? %>
      <%= responsive_image_tag blob %>
    <% end %>

    <% if caption = blob.try(:caption) %>
      <figcaption class="attachment__caption">
        <%= caption %>
      </figcaption>
    <% end %>
  </figure>
<% end %>

<% if local_assigns[:fullscreen] || controller.class.module_parent == Admin || @content.nil? || native_app? %>
  <%= blob_html %>
<% else %>
  <modal-link href="<%= url_for([blob, content_id: @content.id]) %>" rel="nofollow">
    <%= blob_html %>
  </modal-link>
<% end %>
# app/helpers/active_storage_helper.rb

module ActiveStorageHelper
  # ...
  def responsive_image_tag(blob, widths: [640, 1024, 1440, 1920], sizes: "100vw", **options)
    return unless analyze_blob(blob)
    image_tag(blob, srcset: srcset_for(blob, widths:), sizes:, **options)
  end

  def srcset_for(blob, widths:)
    return unless (blob_width, blob_height = blob_size(blob))
    widths
      .filter { |width| width <= blob_width }
      .tap { |w| w.append(blob_width) if blob_width < widths.max }
      .map do |width|
        height = (1.0 * width / blob_width * blob_height).to_i
        [rails_storage_proxy_url(blob_thumb(blob, [width, height])), "#{width}w"]
      end
  end

  private

  def analyze_blob(blob)
    if !blob.is_a?(ActiveStorage::Attached) || blob.attached?
      blob.tap { |blob| blob.analyze unless blob.analyzed? }
    end
  end

  def blob_size(blob)
    analyze_blob(blob)&.metadata&.values_at(:width, :height)
  end
end

@adrianthedev
Copy link
Collaborator

There's one thing that you should try.

In an initializer (can be in avo.rb), you should add this code to make the helper available to Avo's ApplicationController.

# avo.rb (or a different initializer)
Avo.configure do |config|
  # your configs
end

# during Avo's initializing process we run this callback
Rails.configuration.to_prepare do
  # make all your app's helpers available inside the Avo context
  Avo::ApplicationController.helper Rails.application.helpers
end

@gabrielgiroe1 can you please add this in our documentation as well?
Let's add copy with the use case. Maybe from this issue, but just what's important, or maybe try to use a helper method inside an ejected partial (open to suggestions, but it has to be clear to the user reading this).
Also let's add the code that makes this happen.

Closing fornow as I was able to reproduce the fix on my end but please @sedubois let me know if this still persists and you need us to reopen.

@github-project-automation github-project-automation bot moved this to Done in Issues Apr 1, 2024
@adrianthedev adrianthedev changed the title Embedding images in Trix editor does not work Embedding images in Trix editor does not work (app helpers not available in Avo) Apr 1, 2024
@gabrielgiroe1
Copy link
Contributor

Yes, sure. I will add it to the documentation.

@sedubois
Copy link
Contributor Author

sedubois commented Apr 1, 2024

Thanks @adrianthedev that helps, see updated code here, however still 2 issues:

  • how to fix the broken layout shown in this comment? Apparently because of <trix-editor> tag having inline-flex; it seems to be fixed when manually removing it from the DOM. It seems to be coming from Avo::ApplicationHelper#input_classes.
  • wouldn't it make sense for Avo to support Action Text out of the box instead of needing all these monkey-patches in userland?

@sedubois
Copy link
Contributor Author

sedubois commented Apr 1, 2024

OK I can workaround the layout issue as follows:
sedubois/avo-debug@59fa6f0

But it feels to me like there might be a better fix and all this would better be done within Avo.

I don't understand how the initial Avo Trix edit component is working, as it also has the inline-flex CSS class and seemed to be rendering fine?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

4 participants