administrate icon indicating copy to clipboard operation
administrate copied to clipboard

Have a NESTED_ATTRIBUTES configuration to control what is being shown for HasOne relations

Open bo-oz opened this issue 5 years ago • 2 comments

  • What would you like to be able to do? Can you provide some examples?

On the show page of model A, I'd like to show details of model B (A has_one B). Currently administrate fetches the configuration from FORM_ATTRIBUTES, I'd like to have more control by separating this definition into it's own configuration: NESTED_ATTRIBUTES (for instance)

  • How could we go about implementing that?

Probably some reconfiguration of the Field::HasOne class

  • Can you think of other approaches to the problem?

Create my own custom field to handle this, but it seems to be a valuable addition to the current solution. You could even overwrite NESTED_ATTRIBUTES = FORM_ATTRIBUTES in the Administrate::BaseDashboard for backwards compatibility.

bo-oz avatar Feb 25 '20 20:02 bo-oz

The problem I see with the NESTED_ATTRIBUTES approach is that it's not very generic. If we wanted to show different nested attributes for the same model on different dashboards, it wouldn't be possible.

Perhaps a better approach would be to have the list of attributes as an option to the field. Something like this:

# Dashboard definition for "child" model
class ProductDashboard < Administrate::BaseDashboard
  ATTRIBUTE_TYPES = {
    created_at: Field::DateTime,
    updated_at: Field::DateTime,
    description: Field::Text,
    image_url: Field::Url,
    name: Field::String,
    price: Field::Number.with_options(prefix: "$", decimals: 2),
    product_meta_tag: Field::HasOne,
  }
  #...
end

# One "parent" dashboard
class LineItemDashboard < Administrate::BaseDashboard
  ATTRIBUTE_TYPES = {
    # ...
    product: Field::BelongsTo.with_options(attributes: [:name, :price]),
    # ...
  }
  
# Different "parent" dashboard
class MarketingFeatureDashboard < Administrate::BaseDashboard
  ATTRIBUTE_TYPES = {
    # ...
    product: Field::BelongsTo.with_options(attributes: [:name, :image_url, :description]),
    # ...
  }

Thinking about how this could be achieved, I had a look at the code. The dashboard pages are rendered from the views at app/views/administrate/application (see show.html.erb, etc). These in turn get their data from the Administrate::Page::Show, etc presenters, and these get the lists of attributes from the dashboards.

Again as a first look into the problem, it looks to me as though it should be possible to feed that new option attributes from the template and presenter into Administrate::Page::Show, so that it returns the desired field information, and the template renders that instead of the default.

There would be at least one open question, which is: what if we wanted the index and show pages show different attributes for the associated, "child" field? However I think this could be done in the future with specialised form_attributes and show_attributes options, leaving attributes still valid, as a default for both.

I would be willing to look into a PR for this. Would you be game? I'm happy to provide guidance.

pablobm avatar Mar 05 '20 11:03 pablobm

While this is addressed, I proposed a workaround at StackOverflow: https://stackoverflow.com/questions/67129863/show-administrate-attribute-in-one-area-but-not-in-another

pablobm avatar Apr 23 '21 21:04 pablobm