Collection link for STI model
- What were you trying to do? Hello, I have a dashboard that have multiple items in a collection. In the dashboard, I have this relation:
messages: Field::HasMany.with_options(sort_by: :created_at, direction: :desc)
My message class is an STI and only use child as real type. For example:
class Request < Message
Currently, in this display, each line isn't clickable because the class is Request instead of Message.
How can I make the STI subclass use the main class for all things related to Administrate (route, dashboard, etc).
- What versions are you running?
- Rails: 7.2.2.1
- administrate: 0.20.1
Have you tried using:
:class_name (deprecated) - Specifies the name of the associated class.
From: https://administrate-demo.herokuapp.com/customizing_dashboards
It is listed as deprecated but it's something we've realised can't be removed.
I tested this:
messages: Field::HasMany.with_options(sort_by: :created_at, direction: :desc, class_name: 'Message')
But still with this no link are created when rendering the line in the collection table, so no click are possible.
But going to /admin/messages/id correctly display the item. I would like to have this link added directly in the index page or the collection in the Show page with a field that use the hasMany.
Using the class_name seems to detect the correct the dashboard, but no link are created on the index.
It looks like the problem comes from this method in application_helper.rb
def accessible_action?(target, action_name)
target = target.to_sym if target.is_a?(String)
target_class_or_class_name =
target.is_a?(ActiveRecord::Base) ? target.class : target
existing_action?(target_class_or_class_name, action_name) &&
authorized_action?(target, action_name)
end
No where we check the property class_name here and we keep the target name.
Ah, I see. This seems like a bug we should go about fixing. Would you be able to contribute a PR for that?
Currently I don't have the time to do so but maybe on my day off I will take a look at it.
I may have a quick fix that could work but I don't know if this is the best way to do it. Keep in mind the code is just a early version.
Inside the accessible_action? method we could check for the presence of a base class if the target is a ActiveRecord::Base:
target_class_or_class_name, base_class =
target.is_a?(ActiveRecord::Base) ? [target.class, target.class.base_class] : [target, nil]
if (existing_action?(target_class_or_class_name, action_name) && authorized_action?(target, action_name))
return true
elsif base_class.present?
return existing_action?(base_class, action_name) && authorized_action?(target, action_name)
end
But doing so create an error when calling the polymorphic_path method from ActionDispatch inside the _collection.html.erb file.
And in order to keep compatibility with people that create dedicated path for each sub-class, we need to do this kind of thing:
if the resource has existing action, use resource
elsif the resource base class has existing action, use resource.becomes(resource.class.base_class)
else print the resource without link
I'm not sure it's the best way to do it and if this is an acceptable solution, is it better to introduce an helper function that transform the resource and return it, or do the transformation inside the html.
What do you think ?
We're facing the same issue. Any progress on this? @gh-axel-czarniak @nickcharlton. Fix would be much appreciated 🙏
Hello, no solution on my side. Still waiting for an answer from maintainer
I managed to get this to work by overriding the .model_name for the STI models in addition to the fix suggested by @gh-axel-czarniak in https://github.com/thoughtbot/administrate/issues/2813#issuecomment-2752522686.
def self.model_name
return super if self == Message
Message.model_name
end
If you want Administrate to treat the subclasses separately from the base class, you can just leave out the .model_name override.
I opened a PR with the changes - https://github.com/thoughtbot/administrate/pull/2859. It will cause breakage for people that started relying on this bug. I added a note about that in the PR. We can discuss potential ways to mitigate that there.
Until #2859 gets merged, adding this following monkey-patch works thanks to @matteeyah and @gh-axel-czarniak
# config/initializers/administrate_sti_row_links.rb
Rails.application.config.to_prepare do
module Administrate
module ApplicationHelper
def accessible_action?(target, action_name)
target = target.to_sym if target.is_a?(String)
target_class, base_class =
if target.is_a?(ActiveRecord::Base)
[target.class, target.class.base_class]
else
[target, nil]
end
(existing_action?(target_class, action_name) &&
authorized_action?(target, action_name)) ||
(base_class.present? &&
existing_action?(base_class, action_name) &&
authorized_action?(target, action_name))
end
end
end
end