Support all ransack predicates
I made the following changes to enable the use of Ransack's extensive predicates expressions, in addition to ransackable_scope. Please review and let me know if any further changes are needed.
Changes
- Add
AdministrateRansack.ransack?helper to check if a field name with predicates is valid. - Fix the labels to enable automatic translation of field names with predicates in i18n.
Breaking changes
- Drop
admin_scopeoption- For associations,
admin_scopeis no longer necessary as updated to useField.associated_resourceto get the collection. - If we want to do something similar, we can do it with Field::BelongsTo like this:
-
Field::BelongsTo.with_options(scope: ->{ Post.published })
-
- Since
Field::HasManydoes not have ascopeoption, it cannot be done in the same way, but it can be achieved using theField::ScopedHasManyplugin.
- For associations,
- Drop
admin_labeloption- For associations, use the value of
display_resourceas the label to match the title or heading of each admin pages.
- For associations, use the value of
Hey @goosys Sorry for the loong delay on this PR. I came back only recently to this project.
Thank you very much for your contribution here. But I prefer to avoid merging this PR for a couple of reasons:
- it contains breaking changes (the removal of
admin_label) (which can be fine but they will need to wait a major version, plus I prefer to have them isolated in a specific PR); - it contains changes of different kind, I usually try to make the scope as small as possible for maintainability and clean history.
Since it passed quite some time, I'll evaluate to create specific PRs based on this one :+1:
I also think the general idea is good, though I believe some of the details still need further discussion.
For example, there's quite a bit of logic in the view files right now, and I think we should try to separate that more cleanly.
Administrate still supports Rails 6.0, but since this gem has already dropped it, we could consider using Renderable Object from Rails 6.1 to encapsulate the logic. What do you think?
I also think the general idea is good, though I believe some of the details still need further discussion. For example, there's quite a bit of logic in the view files right now, and I think we should try to separate that more cleanly.
Administrate still supports Rails 6.0, but since this gem has already dropped it, we could consider using
Renderable Objectfrom Rails 6.1 to encapsulate the logic. What do you think?
Those fields' view does their job for me, but any improvement could be nice (if proposed in a specific PR).
Do you mean having something similar to view components? My fear using that approach is related to the complexity of the views, for example I wonder how a view like app/views/administrate_ransack/components/_field_has_many.html.erb could become.
The ViewComponent library is separate from Rails itself — Rails only provides support for Renderable objects.
Thanks to the render_in method, we can now pass objects that implement it directly to the render helper.
This allows us to encapsulate business logic within a Renderable object instead of putting it in the view.
Here’s a simplified example. A lot is omitted, but this is the general idea:
By moving business logic out of the view files, the views themselves become much cleaner and easier to maintain.
# lib/administrate_ransack/view/field/base.rb
module AdministrateRansack
module View
module Field
class Base
def initialize(); end
def render_in(view_context); end
def render?; end
private
def ransack?; end
# lib/administrate_ransack/view/field/has_many.rb
module AdministrateRansack
module View
module Field
class HasMany < Base
def render_in(view_context)
@view_context = view_context
return unless render?
view_context.render template_name, local_assigns
end
def render?
super && model.reflections[field.to_s]
end
private
def template_name
"components/field_has_many"
end
def local_assigns
{
form: @form,
field_key: field_key,
resource_field: resource_field,
collection: collection
}
end
...
<%# app/views/administrate_ransack/_filters.html.erb %>
...
<% component = AdministrateRansack::FILTERS[input_type] || 'field_other' %>
<% view_component = <<Some logics to find view class like `AdministrateRansack::View::Field::HasMany`>> %>
<div class="filter filter-...">
<%= render view_component.new(
form: f, model: model, field: field, label: label, type: type, options: options[field]
) %>
<%# app/views/administrate_ransack/components/_field_has_many.html.erb %>
<%= form.label(label || field_key, class: 'filter-label') %>
<%= form.select(field_key, collection, {}, multiple: true) %>
What do you think? Do you think it's worth discussing further?
If it seems promising, I'd be happy to open a dedicated issue and PR for it — would you be willing to take a look if I do?
What do you think? Do you think it's worth discussing further? If it seems promising, I'd be happy to open a dedicated issue and PR for it — would you be willing to take a look if I do?
Yep, the approach is similar to view components.
I'll evaluate better your proposal, but to be honest I'm thinking to go in a different direction at the moment. Recently I started to work to a major refactoring, here is a preview: https://github.com/blocknotes/administrate_ransack/pull/44/files
In this way I'll be able to have simpler views and more freedom on the filters customization:
RANSACK_SEARCH = {
title: {
type: :string,
param: :title_cont
},
published: :boolean,
position: :number,
by_category: {
type: :string,
scope: true
},
dt: :date,
}
I do not exclude the possibility to use renderable / view components / Phlex in the future.