administrate
administrate copied to clipboard
Filtering Field::HasMany
- What would you like to be able to do? Can you provide some examples?
See, I've got a lot of users with different characteristics on my app. For example, they all have a role, which is an enum. Some models have references to users, but some of them have restrictions related to roles. For example, you can't select an user who's a guess to be the editor on a post. I've got all of that figured out via validations, but it would be nice to have it reflected on the interface. As if, when I start editing the editors attribute on a certain post, only users with the role author or admin appear as options.
- How could we go about implementing that?
Passing some kind of filter (maybe a function) to the field on user_dashboard.rb would be nice.
- Can you think of other approaches to the problem?
I could just filter it out during rendering (modifying the partial for Field::HasMany), but that's not nice to do if I want to do it on a lot of dashboards with many different conditions. A minimal example on how to do this would be extremely useful to me.
I also had to go with modifying the partial.
Yeah, I don't think there's a way to do this at the moment. Perhaps it would be a good idea to add a new option to the field that allows for this. It would probably have to modify HasMany#candidate_resources to use this new option. This is the concerned code:
https://github.com/thoughtbot/administrate/blob/b3bb0a3b7833deceff71cfe1687ac36cec12a6e8/lib/administrate/field/has_many.rb#L85-L92
Perhaps someone would like to volunteer a PR?
I prepared a very rudimentary implementation here, but it's not that thought out. It would be probably better to pass scopes rather than plain where instructions, and I don't know how to filter with model methods. It's a start though.
https://github.com/vijuarez/administrate/blob/fd157d238f7f0049afac18edba1be22655c9cf3e/lib/administrate/field/has_many.rb#L85-L100
Yup, that's the sort of thing we would need. I think it could be done better if it accepted a call-able instead, like a lambda. This is what we already do for Select and BelongsTo. For example:
https://github.com/thoughtbot/administrate/blob/9071a7eff60cbbcaf0ddc1b7bfb6bfe7d22b0028/lib/administrate/field/select.rb#L16-L23
Hi! Stumbled upon this issue while needing filtering on HasMany as well.
Based on current implementation for BelongsTo, would it make sense to emulate it in HasMany?:
https://github.com/thoughtbot/administrate/compare/main...benoror:administrate:patch-1
Found this extension that can achieve the same thing: https://github.com/XPBytes/administrate-field-scoped_has_many
it would be great to just get this in here because that extension doesnt provide support for nice many-to-many fields etc, its just an awful html multiselect which is impossible to use for large options
@9mm FWIW I ended up going back to default field and using this approach to scope results:
- https://github.com/thoughtbot/administrate/blob/main/docs/guides/scoping_has_many_relations.md
- https://github.com/SpointMX/spoint-backend/commit/6867623ffc46f64ea1a8cb745043cecff5ba96a0
Awesome, thanks!
I ended up disliking the Dropdown component used in XPBytes/administrate-field-scoped_has_many due to usability reasons.
I tried coming back to using the OG HasMany implementation from Administrate and the before-mentioned https://github.com/thoughtbot/administrate/blob/main/docs/guides/scoping_has_many_relations.md guide, but faced issues with :source param in a :through relationship, similarly as exposed here: https://github.com/thoughtbot/administrate/issues/681
I ended up MonkeyPatching to support a scope option, inspired by the [https://github.com/XPBytes/administrate-field-scoped_has_many/blob/4f13967cb405b94829ae75a22f100d29f2743b2c/lib/administrate/field/scoped_has_many.rb#L24C1-L29C1](very same XPBytes overriden implementation):
module Administrate
module Field
class HasMany < Associative
private
def candidate_resources
puts options[:scope]
scope = options[:scope] ? options[:scope].call(self) : associated_class.all
scope = scope.includes(*options.fetch(:includes)) if options.key?(:includes)
scope
end
end
end
end