Skip to content

Upgrade guide

We'll update this page when we release new Avo 3 versions.

If you're looking for the Avo 2 to Avo 3 upgrade guide, please visit the dedicated page.

Upgrade from 3.5.4 to 3.5.5

Record errors

With version 3.5.5 we introduced a stricter error check. Now when the record have any error included the action will fail. This allow you to do things like:

ruby
before_update do
  if validation_fail?
    errors.add(:field_id, "Error message")
  end
end

Upgrade from 3.4.2 to 3.4.3

turbo configuration

In version 3.4.2 we introduced turbo configuration with instantclick option. We decided that instant_click is a more appropriate name.

ruby
config.turbo = {
  instantclick: true
  instant_click: true
}

Upgrade from 3.4.1 to 3.4.2

Basic Filters URL param changed to encoded_filters

When we added the Dynamic Filters feature, by mistake we introduced a bug where you couldn't use the Basic and Dynamic Filters together because they are both using the filters URL param.

This is not what we intended.

To fix this we are changing the URL param of the Basic Filters from filters to encoded_filters so now you can have a URL with both filters.

md
# Before
https://example.com/avo/resources/users?filters[first_name][contains][]=Jason&page=1&filters=eyJBdm86OkZpbHRlcnM6OklzQWRtaW4iOlsiYWRtaW5zIl19

# After
https://example.com/avo/resources/users?filters[first_name][contains][]=Jason&page=1&encoded_filters=eyJBdm86OkZpbHRlcnM6OklzQWRtaW4iOlsiYWRtaW5zIl19

What to do?

If you have hardcoded links where you reference the filters param, change that to encoded_filters. These links might be in Tools, Resource Tools, Menu Items, or regular view partials (yes, basically anywhere you might have added them 🫤).

A quick search through your codebase should reveal them.

Add active_record_extended gem to your Gemfile

In order to extend Avo's filtering capabilities for arrays and tags fields, we use the active_record_extended gem.

This gem uses postgres and was breaking for those who use any other database like sqlite.

If you want to keep Contained in option on arrays and tags filters you should include the active_record_extended gem to your Gemfile.

Multiple action flux

First iteration of multiple action flux was using redirect_to with turbo_frame: "actions_show". With the update to turbo 8 the redirect was giving some troubles and we decided that is time to improve this experience with a proper response type, navigate_to_action.

If you have a multiple action flux implemented with redirect_to you should change it to navigate_to_action.

Action link_arguments method handles the arguments encoding and encryption internally now so you only need to pass the arguments as a hash and the returned path will already include the encoded arguments.

ruby
field :name,
  as: :text,
  filterable: true,
  name: "name (click to edit)",
  only_on: :index do

  arguments = Base64.encode64 Avo::Services::EncryptionService.encrypt( 
    message: {                                                          
      cities: Array[resource.record.id],                                
      render_name: true
    },                                                                  
    purpose: :action_arguments
  )                                                                     

  arguments = {                                                         
    cities: Array[resource.record.id],                                  
    render_name: true
  }                                                                     

  path, data = Avo::Actions::City::Update.link_arguments(
    resource: resource,
    arguments: arguments
  )

  link_to resource.record.name, path, data: data
end

resource.record or record as nil on visibility blocks

You may notice that resource.record == nil on some visibility blocks. That happens when evaluating the field visibility to render header columns. On index, there is no record.

This is a consequence of a bug fix where resource.record was wrongly storing the last record of the index table.

Check this discussion for more details

Upgrade from 3.3.0 to 3.4.0

Ruby 3.0 is end-of-life and we pushed some code that only works with Ruby 3.1.

Upgrade from 3.2.2 to 3.3.0

may_download_file deprecated

Actions now fully operate with turbo leading to the deprecation of may_download_file option. It can be safely removed from all actions.

Status field failed_when and loading_when default to and empty array

We found some issues with declaring defaults to failed_when and loading_when field options so we are now defaulting them to empty arrays.

If you need that behavior back, add it to your fields.

ruby
field :status,
  as: :status,
  failed_when: [:failed],
  loading_when: [:waiting, :running]

Scopes namespace change

Scopes changed namespace from Avo::Pro::Scopes to Avo::Advanced::Scopes.

TailwindCSS integration

The symlink generated by avo:sym_link task was renamed from tmp/avo/base.css to tmp/avo/avo.base.css. If your application has the TailwindCSS integration generated before Avo 3.3.0 you should replace @import '../../../../tmp/avo/base.css'; with '../../../../tmp/avo/avo.base.css'; in app/assets/stylesheets/avo/avo.tailwind.css.

css
/* app/assets/stylesheets/avo/avo.tailwind.css */

@import '../../../../tmp/avo/base.css'; // [!code --]
@import '../../../../tmp/avo/avo.base.css';

Upgrade from 3.1.3 to 3.1.4

Avo::Filters::BaseFilter.decode_filters

We removed the rescue that would return {} on parsing error. This rescue block was occasionally concealing pertinent errors. Ensure that when invoking Avo::Filters::BaseFilter.decode_filters the argument is not nil and has been encoded using the Avo::Filters::BaseFilter.encode_filters method.

Upgrade from 3.0.1.beta24 to 3.0.2

We introduced the main_panel option and also refactored the way that fields are fetched from the resource, now we allow multiple sidebars per panel but each sidebar should be defined inside a panel or main_panel block.

We suggest to read panels and sidebars sections for more information and to be aware of the new possibilities.

Dashboards visibility and authorization

Previously, if the visible attribute was set to false on dashboards, visiting them was impossible because the controller would trigger a "Not found" error. In cases where authorize returned false, the controller would block access but still keep the dashboard visible.

This behavior has been enhanced. Now, even if visible is set to false, the dashboard remains accessible but won't appear in the menu. Additionally, if authorize returns false, the dashboards are now hidden.

Actions

We've internally implemented some changes around actions to resolve certain bugs. No action is needed from your end, but if you happen to notice any anomalies in the actions flow, please get in touch with us so we can address them promptly. Thank you.

Attachments eager load

Attachments are no longer automatically eager loading. If you want to eager load attachments there are at least two ways:

Use self.includes option

ruby
class Avo::Resources::PhotoComment < Avo::BaseResource
  self.includes = [:user, [photo_attachment: :blob]]

  def fields
    field :user, as: :belongs_to
    field :photo, as: :file, is_image: true
  end

Use self.index_query option

ruby
class Avo::Resources::Product < Avo::BaseResource
   self.index_query = -> {
    query.includes image_attachment: :blob
  }

  def fields
    field :image, as: :file, is_image: true
  end

Upgrade from 3.0.1.beta23 to 3.0.1.beta24

Cards

With the new feature that allow cards on resources we've realized that it's no longer logical to retain cards within the Dashboard namespace scope. Consequently, each card is now located within the Avo::Cards namespace.

ruby
# Before
class Avo::Cards::AmountRaised < Avo::Dashboards::MetricCard
class Avo::Cards::ExampleAreaChart < Avo::Dashboards::ChartkickCard
class Avo::Cards::ExampleBarChart < Avo::Dashboards::ChartkickCard
# ...

# After
class Avo::Cards::AmountRaised < Avo::Cards::MetricCard
class Avo::Cards::ExampleAreaChart < Avo::Cards::ChartkickCard
class Avo::Cards::ExampleBarChart < Avo::Cards::ChartkickCard
# ...

Upgrade from 3.0.1.beta22 to 3.0.1.beta23

Caching

Since there are many available cache stores and we were allowing only few we changed the way of computing the cache store to be used by Avo.

One of our concerns was to maintain the status quo, but if you notice any caching issues there is a new configurable option config.cache_store that allows you to tell Avo what cache_store to use.

Check cache page for more details.

Upgrade from 3.0.1.beta8 to 3.0.1.beta9

Heading as field

Heading option changed declaration mode, one of the main reasons for this change is to be able to generate a clear data-field-id on the DOM

For more information about heading field syntax check heading field's documentation.

ruby
heading "personal information"
heading "contact"
heading '<div class="underline uppercase font-bold">DEV</div>', as_html: true
ruby
field :personal_information, as: :heading       # data-field-id == "personal_information"
field :heading, as: :heading, label: "Contact"  # data-field-id == "heading"
field :dev, as: :heading, as_html: true, label: '<div class="underline uppercase font-bold">DEV</div>'

Badge field secondary option renamed to neutral

We believe that the term neutral better reflects the intended use.

ruby
field :stage,
  as: :badge,
  options: {
    info: [:discovery, :idea],
    success: :done,
    warning: "on hold",
    danger: :cancelled,
    secondary: :drafting
  }
ruby
field :stage,
  as: :badge,
  options: {
    info: [:discovery, :idea],
    success: :done,
    warning: "on hold",
    danger: :cancelled,
    neutral: :drafting
  }

link_to_resource was renamed to link_to_record.

ruby
class Avo::Resources::User < Avo::BaseResource
  def fields
    field :id, as: :id, link_to_resource: true
    field :email, as: :gravatar, link_to_resource: true
  end
end
ruby
class Avo::Resources::User < Avo::BaseResource
  def fields
    field :id, as: :id, link_to_record: true
    field :email, as: :gravatar, link_to_record: true
  end
end

Upgrade from 3.0.1.beta5 to 3.0.1.beta6

The status field changed behavior

Before, for the status you'd set the failed and loading states and everything else fell under success. That felt unnatural. We needed a neutral state. Now we changed the field so you'll set the failed, loading, and success values and the rest fall under neutral.

ruby
# Before
field :status,
  as: :status,
  failed_when: :failed,
  loading_when: :loading

# After
field :status,
  as: :status,
  failed_when: :failed,
  loading_when: :loading
  success_when: :deployed # specify the success state