Skip to content

Commit

Permalink
Fix partials to support all ransack predicates
Browse files Browse the repository at this point in the history
  • Loading branch information
goosys committed Jul 26, 2024
1 parent 7605b61 commit 7d9478a
Show file tree
Hide file tree
Showing 19 changed files with 127 additions and 43 deletions.
17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,14 @@ end
+ `attribute_types`: hash used to specify the filter fields, ex. `{ title: Administrate::Field::String }`
+ `search_path`: the path to use for searching (form URL)
+ `namespace`: the namespace used by Administrate, ex. `:supervisor`
- For associations (_has many_/_belongs to_) the label used can be customized adding an `admin_label` method to the target model which returns a string while the collection can by filtered with `admin_scope`. Example:
- For associations (_has many_/_belongs to_) the label used can be customized adding an `display_resource` method to the target dashboard which returns a string. Example:

```rb
# Sample post model
class Post < ApplicationRecord
scope :admin_scope, -> { where(published: true) }

def admin_label
title.upcase
class PostDashboard < Administrate::BaseDashboard
# Overwrite this method to customize how posts are displayed
# across all pages of the admin dashboard.
def display_resource(post)
"##{post.id} #{post.title&.upcase}"
end
end
```
Expand Down Expand Up @@ -139,9 +138,11 @@ end
# In alternative prepare an hash in the dashboard like RANSACK_TYPES = {}
attribute_types = {
title: Administrate::Field::String,
title_or_description_cont: Administrate::Field::String,
author: Administrate::Field::BelongsTo,
category: Administrate::Field::Select.with_options(collection: Post.categories.to_a),
published: Administrate::Field::Boolean
published: Administrate::Field::Boolean,
updated_at_lteq: Administrate::Field::Date
}
attribute_labels = {
author: 'Written by',
Expand Down
2 changes: 1 addition & 1 deletion app/views/administrate_ransack/_filters.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<% attribute_types.each do |field, type| %>
<% next if field == :id %>
<% label = attribute_labels.include?(field) ? attribute_labels[field] : field %>
<% label = attribute_labels.include?(field) ? attribute_labels[field] : nil %>
<% model = @ransack_results.klass %>
<% input_type = type.is_a?(Administrate::Field::Deferred) ? type.deferred_class.to_s : type.to_s %>
<% component = AdministrateRansack::FILTERS[input_type] || 'field_other' %>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<% association = model.reflections[field.to_s] %>
<% if association %>
<% field_key = model.ransackable_scopes.include?(field) ? field : "#{field}_id_eq" %>
<% desc = association.klass.method_defined?(:admin_label) ? :admin_label : :to_s %>
<% collection = association.klass.send(association.klass.respond_to?(:admin_scope) ? :admin_scope : :all) %>
<% field_key = AdministrateRansack.ransack?(model, {field => "1,2"}) ? field : "#{field}_id_eq" %>
<% label ||= AdministrateRansack.ransack?(model, {field => "1,2"}) ? field : "#{field}_id" %>
<% resource_field = type.new(field, nil, Administrate::Page::Collection.new(@dashboard), resource: model.new) %>
<% collection = resource_field.associated_resource_options %>
<%= form.label(label, class: 'filter-label') %>
<%= form.collection_select(field_key, collection, :id, desc, include_blank: true) %>
<%= form.select("#{field}_id_eq", collection, { include_blank: true }, { class: 'selectize' }) %>
<% end %>
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<% field_key = model.ransackable_scopes.include?(field) ? field : "#{field}_eq" %>
<% field_key = AdministrateRansack.ransack?(model, {field => "true"}) ? field : "#{field}_eq" %>
<% values = [[t('administrate_ransack.filters.no'), false], [t('administrate_ransack.filters.yes'), true]] %>
<%= form.label(label, class: 'filter-label') %>
<%= form.label(label || field, class: 'filter-label') %>
<%= form.select(field_key, values, include_blank: true) %>
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<%= form.label(label, class: 'filter-label') %>
<% if model.ransackable_scopes.include?(field) %>
<%= form.label(label || field, class: 'filter-label') %>
<% if AdministrateRansack.ransack?(model, {field => Date.today}) %>
<%= form.date_field(field, value: form.object.send(field)) %>
<% else %>
<%= form.date_field("#{field}_gteq") %>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<%= form.label(label, class: 'filter-label') %>
<% if model.ransackable_scopes.include?(field) %>
<%= form.label(label || field, class: 'filter-label') %>
<% if AdministrateRansack.ransack?(model, {field => DateTime.now}) %>
<%= form.datetime_field(field, value: form.object.send(field)) %>
<% else %>
<%= form.datetime_field("#{field}_gteq") %>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
<% association = model.reflections[field.to_s] %>
<% if association %>
<% field_key = model.ransackable_scopes.include?(field) ? field : "#{field}_id_in" %>
<% desc = association.klass.method_defined?(:admin_label) ? :admin_label : :to_s %>
<% collection = association.klass.send(association.klass.respond_to?(:admin_scope) ? :admin_scope : :all) %>
<% field_key = AdministrateRansack.ransack?(model, {field => "1,2"}) ? field : "#{field}_id_in" %>
<% resource_field = type.new(field, nil, Administrate::Page::Collection.new(@dashboard), resource: model.new) %>
<% collection = resource_field.associated_resource_options %>
<%= form.label(label, class: 'filter-label') %>
<%= form.label(label || field_key, class: 'filter-label') %>
<% if options&.include? 'select' %>
<%= form.select(field_key, nil, {}, multiple: true) do %>
<%= options_from_collection_for_select(collection, :id, desc) %>
<% end %>
<%= form.select(field_key, collection, {}, multiple: true) %>
<% else %>
<%= form.collection_check_boxes(field_key, collection, :id, desc) do |b| %>
<%= form.collection_check_boxes(field_key, collection, :second, :first) do |b| %>
<%= b.label do %>
<%= b.check_box %>
<span><%= b.object.send(desc) %></span>
<span><%= b.text %></span>
<% end %>
<% end %>
<% end %>
Expand Down
11 changes: 7 additions & 4 deletions app/views/administrate_ransack/components/_field_number.html.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<% field_key = model.ransackable_scopes.include?(field) ? field : "#{field}_eq" %>
<%= form.label(label, class: 'filter-label') %>
<%= form.number_field(field_key) %>
<%= form.label(label || field, class: 'filter-label') %>
<% if AdministrateRansack.ransack?(model, {field => "1"}) %>
<%= form.number_field "#{field}" %>
<% else %>
<%= form.number_field "#{field}_gteq" %>
<%= form.number_field "#{field}_lteq" %>
<% end %>
11 changes: 9 additions & 2 deletions app/views/administrate_ransack/components/_field_other.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
<%= form.label(label, class: 'filter-label') %>
<%= form.search_field(field) %>
<% if AdministrateRansack.ransack?(model, {field => "valid"}) %>
<%= form.label(label || field, class: 'filter-label') %>
<%= form.search_field(field) %>
<% elsif AdministrateRansack.ransack?(model, {"#{field}_cont" => "valid"}) %>
<%= form.label(label || "#{field}_cont", class: 'filter-label') %>
<%= form.search_field("#{field}_cont") %>
<% else %>
<%# render nothing %>
<% end %>
<%# unsupported Field::HasOne %>
<%# unsupported Field::Polymorphic %>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<% field_key = model.ransackable_scopes.include?(field) ? field : "#{field}_eq" %>
<% collection = (type.respond_to?(:options) ? type.options[:collection] : []) || [] %>
<%= form.label(label, class: 'filter-label') %>
<%= form.label(label || field, class: 'filter-label') %>
<%= form.select(field_key, collection, include_blank: true) %>
13 changes: 9 additions & 4 deletions app/views/administrate_ransack/components/_field_string.html.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
<% field_key = model.ransackable_scopes.include?(field) ? field : "#{field}_cont" %>
<%= form.label(label, class: 'filter-label') %>
<%= form.search_field(field_key) %>
<% if AdministrateRansack.ransack?(model, {field => "valid"}) %>
<%= form.label(label || field, class: 'filter-label') %>
<%= form.search_field(field) %>
<% elsif AdministrateRansack.ransack?(model, {"#{field}_cont" => "valid"}) %>
<%= form.label(label || "#{field}_cont", class: 'filter-label') %>
<%= form.search_field("#{field}_cont") %>
<% else %>
<%# render nothing %>
<% end %>
2 changes: 2 additions & 0 deletions spec/dummy/app/controllers/admin/authors_controller.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
module Admin
class AuthorsController < Admin::ApplicationController
prepend AdministrateRansack::Searchable

# Overwrite any of the RESTful controller actions to implement custom behavior
# For example, you may want to send an email after a foo is updated.
#
Expand Down
10 changes: 10 additions & 0 deletions spec/dummy/app/dashboards/author_dashboard.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ class AuthorDashboard < Administrate::BaseDashboard
# published_posts
# recent_posts

# RANSACK_TYPES
RANSACK_TYPES = {
posts: Field::HasMany,
tags: Field::HasMany,
name: Field::String,
name_or_email_cont: Field::String,
name_not_cont: Field::String,
age: Field::Number
}.freeze

# SHOW_PAGE_ATTRIBUTES
# an array of attributes that will be displayed on the model's show page.
SHOW_PAGE_ATTRIBUTES = %i[
Expand Down
6 changes: 3 additions & 3 deletions spec/dummy/app/dashboards/tag_dashboard.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class TagDashboard < Administrate::BaseDashboard
# Overwrite this method to customize how tags are displayed
# across all pages of the admin dashboard.
#
# def display_resource(tag)
# "Tag ##{tag.id}"
# end
def display_resource(tag)
"##{tag.id} #{tag.name}"
end
end
17 changes: 17 additions & 0 deletions spec/dummy/app/views/admin/authors/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<section class="main-content__body main-content__body--flush">
<%= render(
"collection",
collection_presenter: page,
collection_field_name: resource_name,
page: page,
resources: resources,
table_title: "page-title"
) %>
<%= paginate resources, param_name: '_page' %>
</section>

<%= render(
'administrate_ransack/filters',
attribute_types: @dashboard.class::RANSACK_TYPES
) %>
1 change: 1 addition & 0 deletions spec/dummy/app/views/admin/posts/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
category: Administrate::Field::Select.with_options(collection: Post.categories.to_a),
published: Administrate::Field::Boolean,
position: Administrate::Field::Number,
position_eq: Administrate::Field::Number,
tags: Administrate::Field::HasMany,
dt: Administrate::Field::Date,
created_at: Administrate::Field::DateTime,
Expand Down
2 changes: 1 addition & 1 deletion spec/rails_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def setup_data
author = Author.find_by!(name: 'A test author')
tag = Tag.find_by!(name: 'A test tag')
Post.first.update!(title: 'A post', author: author, category: 'news', published: true, dt: Time.zone.today)
Post.second.update!(title: 'Another post', author: author, category: 'story', dt: Date.yesterday, tags: [tag])
Post.second.update!(title: 'Another post', author: author, category: 'story', position: 123, dt: Date.yesterday, tags: [tag])
Post.third.update!(title: 'Last post', author: author, category: 'news', position: 234, dt: Date.tomorrow)
end
end
Expand Down
12 changes: 12 additions & 0 deletions spec/system/number_filter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@

RSpec.describe 'Number filter' do
let(:post3) { Post.third }
let(:author1) { Author.first }

it 'filters the authors by age range', :aggregate_failures do
visit '/admin/authors'

fill_in('q[age_lteq]', with: '28')
find('input[type="submit"]').click

expect(page).to have_current_path %r{/admin/authors\?.+q%5Bage_lteq%5D=28.*}
expect(page).to have_css('.js-table-row', count: 2)
expect(page).to have_css('.js-table-row a.action-show', text: author1.name)
end

it 'filters the posts by position', :aggregate_failures do
visit '/admin/posts'
Expand Down
27 changes: 27 additions & 0 deletions spec/system/string_filter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,33 @@

RSpec.describe 'String filter' do
let(:post2) { Post.second }
let(:author11) { Author.find(11) }

it 'filters the authors by name or email', :aggregate_failures do
visit '/admin/authors'

fill_in('q[name_or_email_cont]', with: '@bbb')
find('input[type="submit"]').click

expect(page).to have_css('.js-table-row', count: 1)
expect(page).to have_css('.js-table-row a.action-show', text: author11.name)

fill_in('q[name_or_email_cont]', with: 'A test')
find('input[type="submit"]').click

expect(page).to have_css('.js-table-row', count: 1)
expect(page).to have_css('.js-table-row a.action-show', text: author11.name)
end

it 'filters the authors by name not contain', :aggregate_failures do
visit '/admin/authors'

fill_in('q[name_not_cont]', with: 'A test')
find('input[type="submit"]').click

expect(page).to have_css('.js-table-row', count: 10)
expect(page).not_to have_css('.js-table-row a.action-show', text: author11.name)
end

it 'filters the posts by title', :aggregate_failures do
visit '/admin/posts'
Expand Down

0 comments on commit 7d9478a

Please sign in to comment.