2

I'm trying to set up Action Text inside an Administrate Dashboard. I've followed the installation steps on the Rails Guides Overview page. Then when trying to add the attribute to /app/dashboards/lesson_dashboard.rb, I get errors.

When I try body: Field::RichText, I get: uninitialized constant Administrate::Field::RichText

When I try body: ActionText::RichText, I get: wrong number of arguments (given 4, expected 0..1).

When I follow the instructions in the Administrate Wiki, I get undefined method 'body' when it gets to the line with <%= f.rich_text_area field.attribute %>.

Any idea what this attribute is called or why I'm getting these errors?

app/dashboards/lesson_dashboard.rb:

require "administrate/base_dashboard"

class LessonDashboard < Administrate::BaseDashboard
  # ATTRIBUTE_TYPES
  # a hash that describes the type of each of the model's fields.
  #
  # Each different type represents an Administrate::Field object,
  # which determines how the attribute is displayed
  # on pages throughout the dashboard.
  ATTRIBUTE_TYPES = {
    course: Field::BelongsTo,
    documents: Field::ActiveStorage.with_options(
      show_display_preview: false,
      destroy_url: proc do |namespace, resource, document|
        [:delete_document_course, resource, { document_id: document.id }]
      end
    ),
    id: Field::Number,
    title: Field::String,
    # body: Field::Text,
    body: RichTextAreaField,
    created_at: Field::DateTime,
    updated_at: Field::DateTime,
  }.freeze

  # COLLECTION_ATTRIBUTES
  # an array of attributes that will be displayed on the model's index page.
  #
  # By default, it's limited to four items to reduce clutter on index pages.
  # Feel free to add, remove, or rearrange items.
  COLLECTION_ATTRIBUTES = %i[
    title
    course
  ].freeze

  # SHOW_PAGE_ATTRIBUTES
  # an array of attributes that will be displayed on the model's show page.
  SHOW_PAGE_ATTRIBUTES = %i[
    course
    title
    body
    documents
    created_at
    updated_at
  ].freeze

  # FORM_ATTRIBUTES
  # an array of attributes that will be displayed
  # on the model's form (`new` and `edit`) pages.
  FORM_ATTRIBUTES = %i[
    course
    title
    body
    documents
  ].freeze

  # COLLECTION_FILTERS
  # a hash that defines filters that can be used while searching via the search
  # field of the dashboard.
  #
  # For example to add an option to search for open resources by typing "open:"
  # in the search field:
  #
  #   COLLECTION_FILTERS = {
  #     open: ->(resources) { resources.where(open: true) }
  #   }.freeze
  COLLECTION_FILTERS = {}.freeze

  # Overwrite this method to customize how lessons are displayed
  # across all pages of the admin dashboard.
  def display_resource(lesson)
    lesson.title
  end

  # permitted for has_many_attached
  def permitted_attributes
    # super + [:attachments => []]
    super + [:documents => []]
  end

end

app/models/lesson.rb:

class Lesson < ApplicationRecord

  belongs_to :course
  has_many_attached :documents

  validates :title, presence: true

end
Brad West
  • 943
  • 7
  • 19
  • I'm not an administrate user, but some casual googling indicates that you need to create your own custom field type for rich text / ActionText support. Does [this help](https://github.com/thoughtbot/administrate/wiki/Field:-RichTextAreaField) at all? – rmlockerd Aug 15 '21 at 23:22
  • I hadn't found that, thanks for the link. But following it only gave me different errors. I have updated the question. – Brad West Aug 16 '21 at 13:22
  • Could you edit your question to add the code for `lesson_dashboard.rb` and the `Lesson` model? Just for fun I set up a scratch Rails project and went through the ActionText and Administrate guide, and it worked for me. – rmlockerd Aug 17 '21 at 22:49
  • I added the code. Which guide did you use? – Brad West Aug 19 '21 at 11:26

2 Answers2

3

@rmlockerd's answer is excellent - but it's simpler to do this with Rails 7 now that webpacker is not needed for every project.

My tweaks to his process are:

  1. In the newly generated administrate layout file, add these two lines to the <head>:
    <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
    <%= javascript_importmap_tags %>

instead of the javascript_pack_tag. You can also delete the other files that were generated (_flash,_icons etc). Just use the standard administrate ones - unless of course you want to override them.

  1. Not necessary

  2. Not necessary

I am using the rails-tailwind gem in my project, so it's possible that I am already doing the guts of what steps 3 and 4 were already doing in terms of concatenating all these extra styles together.

charlesdeb
  • 571
  • 5
  • 14
2

The ActionText guide and Administrate help have the information, but it is somewhat disjointed across multiple pages, so I've jotted down the steps I used on a fresh Rails 6.1 application.

These steps assume that you have configured ActionText (run rails g action_text:install and run the resulting migrations), and installed/configured the administrate gem.

  1. The Trix rich text editor requires Javascript, which in Rails 6 is loaded with webpack. The default administrate layout isn't webpack-friendly, so you need to customise the layout. Generate layouts to customise:
  % rails generate administrate:views:layout
  1. Add a javascript_pack_tag to views/layouts/admin/application.html.erb to load your application pack:
<head>
...
  <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  <%= render "stylesheet" %>
  <%= csrf_meta_tags %>
...
</head>

The administrate guide steps you through creating a separate pack for administrate JS, but it's only required if you need to customise the JS (e.g., for using flatpickr as date picker). For just using RichText it isn't required, so we just load the main application pack.

  1. You also need to customise the administrate CSS to add the Trix styles. Run the task to generate the custom administrate stylesheets:
% rails generate administrate:assets:stylesheets
  1. Edit administrate stylesheets to include styles for the Trix rich text controls at the bottom:
// Rest of file
...
@import "trix/dist/trix";
@import "selectize";

.trix-content {
  .attachment-gallery {
    > action-text-attachment,
    > .attachment {
      flex: 1 0 33%;
      padding: 0 0.5em;
      max-width: 33%;
    }

    &.attachment-gallery--2,
    &.attachment-gallery--4 {
      > action-text-attachment,
      > .attachment {
        flex-basis: 50%;
        max-width: 50%;
      }
    }
  }

  action-text-attachment {
    .attachment {
      padding: 0 !important;
      max-width: 100% !important;
    }
  }
}

.field-unit--rich-text-area-field {
  .field-unit__field {
    width: 80%;
  }
}
  1. Add a custom field type for rich text editing since Administrate doesn't include one out of the box.
% rails g administrate:field rich_text_area
  1. Edit the input field type in fields/rich_text_area/_form.html.erb to use the Trix rich text control:
<div class="field-unit__field">
  <%= f.rich_text_area field.attribute %>
</div>
  1. Edit your model to add your rich text attribute:
class Lesson < ApplicationRecord
  has_rich_text :body
end
  1. Generate a dashboard for your model:
% rails generate administrate:dashboard Lesson
  1. Edit the field type in dashboards/lesson_dashboard.rb to use the custom field type:
  ATTRIBUTE_TYPES = {
    ...
    rich_text_body: RichTextAreaField,
  }.freeze
  1. Profit: enter image description here
rmlockerd
  • 3,776
  • 2
  • 15
  • 25
  • I've marked this as the correct answer as it does solve the problem I asked ...but, the body content that was in the existing lessons isn't showing. I can save new body content, so I know it's working, but how can I get all the old content into the Trix editor body? Might be worth adding to the answer for posterity. In any event, thanks for your help Rob. – Brad West Aug 23 '21 at 20:17
  • 2
    Did you possibly originally have a `body` attribute directly on the `Lesson` model? ActionText stores `has_rich_text` blobs in a separate table. There's nothing preventing your model from having an attribute with the same name as your blob, but ActionText overrides the accessor method. If that's your situation, you can probably just load the old model attribute value and re-save it (or write a migration to do it). – rmlockerd Aug 23 '21 at 21:21
  • I dont see why you should generate administrate stylesheets ? Just import trix css via webpack and writte your custom css there – David Geismar Feb 08 '22 at 09:26
  • I had to change `rich_text_body` to be just `body` – MIA Jul 07 '22 at 11:58