{"id":13879032,"url":"https://github.com/blocknotes/administrate_ransack","last_synced_at":"2025-05-09T00:03:36.557Z","repository":{"id":40508348,"uuid":"297127466","full_name":"blocknotes/administrate_ransack","owner":"blocknotes","description":"A plugin for Administrate to use Ransack for filtering resources","archived":false,"fork":false,"pushed_at":"2025-05-08T07:47:34.000Z","size":6380,"stargazers_count":32,"open_issues_count":4,"forks_count":19,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-09T00:02:36.244Z","etag":null,"topics":["administrate","rails","ruby","ruby-on-rails"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/blocknotes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"MIT-LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["blocknotes"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2020-09-20T17:25:47.000Z","updated_at":"2025-05-01T19:29:45.000Z","dependencies_parsed_at":"2024-01-13T20:56:40.103Z","dependency_job_id":"e8e84090-84ac-4773-a03a-4ea475515d39","html_url":"https://github.com/blocknotes/administrate_ransack","commit_stats":{"total_commits":96,"total_committers":7,"mean_commits":"13.714285714285714","dds":0.5104166666666667,"last_synced_commit":"722291dd0e08de01d8399cd2b3178634a7e78e3f"},"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blocknotes%2Fadministrate_ransack","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blocknotes%2Fadministrate_ransack/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blocknotes%2Fadministrate_ransack/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blocknotes%2Fadministrate_ransack/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/blocknotes","download_url":"https://codeload.github.com/blocknotes/administrate_ransack/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253166502,"owners_count":21864475,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["administrate","rails","ruby","ruby-on-rails"],"created_at":"2024-08-06T08:02:07.504Z","updated_at":"2025-05-09T00:03:36.469Z","avatar_url":"https://github.com/blocknotes.png","language":"Ruby","readme":"# Administrate Ransack\n[![gem version](https://badge.fury.io/rb/administrate_ransack.svg)](https://badge.fury.io/rb/administrate_ransack)\n[![gem downloads](https://badgen.net/rubygems/dt/administrate_ransack)](https://rubygems.org/gems/administrate_ransack)\n[![linters](https://github.com/blocknotes/administrate_ransack/actions/workflows/linters.yml/badge.svg)](https://github.com/blocknotes/administrate_ransack/actions/workflows/linters.yml)\n[![Specs Rails 8.0](https://github.com/blocknotes/administrate_ransack/actions/workflows/specs_rails80.yml/badge.svg)](https://github.com/blocknotes/administrate_ransack/actions/workflows/specs_rails80.yml)\n\nA plugin for [Administrate](https://github.com/thoughtbot/administrate) to use [Ransack](https://github.com/activerecord-hackery/ransack) for filtering resources.\n\nFeatures:\n- add Ransack search results using module prepend inside an Administrate controller;\n- offer a filters partial based on the resource's attributes;\n- customize searchable attributes.\n\n## Installation\n\n- After installing Administrate, add to *Gemfile*: `gem 'administrate_ransack'` (and execute `bundle`)\n- Edit your admin resource controller adding inside the class body:\n\n```rb\nprepend AdministrateRansack::Searchable\n```\n\n- Add to your resource index view (ex. to generate the index for a Post model: `bin/rails generate administrate:views:index Post`):\n\n```erb\n\u003c%= render('administrate_ransack/filters') %\u003e\n```\n\n- Update your model (ex. Post) exposing the ransackable attributes and associations, skipping this step will raise an exception that explains in details:\n\n```rb\nclass Post \u003c ApplicationRecord\n  # ...\n\n  class \u003c\u003c self\n    def ransackable_attributes(_auth_object = nil)\n      %w[title description]\n    end\n\n    def ransackable_associations(_auth_object = nil)\n      %w[author]\n    end\n  end\nend\n```\n\n- See the Usage section for extra options\n\n## Usage\n\n- The filters partial accepts some optional parameters:\n  + `attribute_labels`: hash used to override the field labels, ex. `{ title: \"The title\" }`\n  + `attribute_types`: hash used to specify the filter fields, ex. `{ title: Administrate::Field::String }`\n  + `search_path`: the path to use for searching (form URL)\n  + `namespace`: the namespace used by Administrate, ex. `:supervisor`\n- 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:\n\n```rb\n# Sample post model\nclass Post \u003c ApplicationRecord\n  scope :admin_scope, -\u003e { where(published: true) }\n\n  def admin_label\n    title.upcase\n  end\nend\n```\n\n- For _has_many_ associations it is possible to use Selectize in place of the checkboxes using:\n\n```erb\n\u003c!-- Set options for an association named: tags --\u003e\n\u003c%= render('administrate_ransack/filters', options: { tags: 'select' } ) %\u003e\n```\n\n- To use scopes in filters it's needed to update also the `ransackable_scopes` in the model, example:\n\n```rb\n# Sample post model\nclass Post \u003c ApplicationRecord\n  scope :recents, -\u003e(dt = 1.month.ago) { where('dt \u003e ?', dt).order(dt: :desc) }\n  scope :by_category, -\u003e(category) { where(category: category) }\n\n  class \u003c\u003c self\n    def ransackable_scopes(_auth_object = nil)\n      %i[by_category recents]\n    end\n  end\nend\n```\n\n```erb\n\u003c!-- Sample index view --\u003e\n\u003c%= render(\n  'administrate_ransack/filters',\n  attribute_types: { recents: Administrate::Field::DateTime, by_category: Administrate::Field::String }\n) %\u003e\n```\n\n## Notes\n\n- Administrate Search logic works independently from Ransack searches, I suggest to disable it eventually (ex. overriding `show_search_bar?` in the controller or removing the bar from the view)\n- Date/time filters use Rails `datetime_field` method which produces a `datetime-local` input field, at the moment this type of element is not broadly supported, a workaround is to include [flatpickr](https://github.com/flatpickr/flatpickr) datetime library.\n  + This gem checks if `flatpickr` function is available in the global scope and applies it to the `datetime-local` filter inputs;\n  + you can include the library using your application assets or via CDN, ex. adding to **app/views/layouts/admin/application.html.erb**:\n\n```html\n  \u003clink rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/flatpickr@4.5.7/dist/flatpickr.min.css\"\u003e\n  \u003cscript src=\"https://cdn.jsdelivr.net/npm/flatpickr@4.5.7/dist/flatpickr.min.js\"\u003e\u003c/script\u003e\n\n  \u003cscript\u003e\n    // optionally change the flatpikr options:\n    window.flatpickr_filters_options = { dateFormat: \"Y-m-d\" };\n  \u003c/script\u003e\n```\n\n## Customizations\n\n- Ransack options can be changed defining a method `ransack_options` in the resource controller\n- The Ransack results by default use _distinct_, to change this behavior it is possible to define a `ransack_result_distinct` method\n- When a search term is not recognized a flash alert is shown (using a value from locales at `administrate_ransack.errors.invalid_search`), a custom behavior can be apply defining a method `invalid_search_callback`\n\n```rb\nmodule Admin\n  class PostsController \u003c Admin::ApplicationController\n    prepend AdministrateRansack::Searchable\n\n    def ransack_options\n      # raises an exception on unknown parameters\n      { ignore_unknown_conditions: false }\n    end\n\n    def ransack_result_distinct\n      # disable distinct\n      false\n    end\n\n    def invalid_search_callback(e)\n      raise e\n    end\n  end\nend\n```\n\n- Sample call of the filters partial with different options provided:\n\n```erb\n\u003c%\n# In alternative prepare an hash in the dashboard like RANSACK_TYPES = {}\nattribute_types = {\n  title: Administrate::Field::String,\n  author: Administrate::Field::BelongsTo,\n  category: Administrate::Field::Select.with_options(collection: Post.categories.to_a),\n  published: Administrate::Field::Boolean\n}\nattribute_labels = {\n  author: 'Written by',\n  title: nil\n}\n%\u003e\n\u003c%= render(\n  'administrate_ransack/filters',\n  attribute_types: attribute_types,\n  attribute_labels: attribute_labels,\n  search_path: admin_root_path\n) %\u003e\n```\n\n- Another option is to prepare some hashes constants in the dashboard (ex. `RANSACK_TYPES`):\n\n```erb\n\u003c%= render('administrate_ransack/filters', attribute_types: @dashboard.class::RANSACK_TYPES) %\u003e\n```\n\n## Sample styles\n\n- Some basic style to setup the filters as a sidebar (see the screenshot below):\n\n```css\n.main-content__body {\n  display: inline-block;\n  width: calc(100% - 320px);\n  vertical-align: top;\n}\n\n[data-administrate-ransack-filters] {\n  display: inline-block;\n  padding-left: 10px;\n  padding-top: 10px;\n  width: 300px;\n}\n\n[data-administrate-ransack-filters] .filter {\n  margin-bottom: 10px;\n}\n\n[data-administrate-ransack-filters] .filters-buttons {\n  margin-top: 30px;\n}\n```\n\nScreenshot:\n![screenshot](extra/screenshot.png)\n\n- Alternative styles for an horizontal search bar:\n\n```css\n[data-administrate-ransack-filters] {\n  border: 1px solid #ddd;\n  padding: 10px;\n  text-align: center;\n}\n\n[data-administrate-ransack-filters] .filters {\n  display: inline-block;\n}\n\n[data-administrate-ransack-filters] .filter, [data-administrate-ransack-filters] .filter \u003e label {\n  display: inline-block;\n}\n\n[data-administrate-ransack-filters] .filter \u003e input {\n  display: inline-block;\n  width: auto;\n}\n\n[data-administrate-ransack-filters] .filters-buttons {\n  display: inline-block;\n  margin-left: 20px;\n}\n```\n\nScreenshot:\n![screenshot2](extra/screenshot2.png)\n\n## Extra notes\n\n- If you need to define custom search logics you can skip prepending the module (`AdministrateRansack::Searchable`) and create your own search query in a controller (but you need to assign the Ransack search object to `@ransack_results` for the filters partial), for example:\n\n```rb\n  def scoped_resource\n    @ransack_results = super.ransack(params[:q])\n    @ransack_results.result(distinct: true)\n  end\n```\n\n- Sometimes it's easier to create a new Ransack field than overriding the search logic (there are a lot of good examples in the [Ransack Wiki](https://github.com/activerecord-hackery/ransack/wiki/Using-Ransackers)), example to search in a `jsonb` field adding to a Post model:\n\n```rb\n  ransacker :keywords do\n    Arel.sql(\"posts.metadata -\u003e\u003e 'keywords'\")\n  end\n```\n\n- With Administrate Ransack you can easily create links to other resources applying some filters, example to add in a tag show page the link to the related posts:\n\n```erb\n  \u003c%= link_to(\"Tag's posts\", admin_posts_path('q[tags_id_in][]': page.resource.id), class: \"button\") %\u003e\n```\n\n## Do you like it? Star it!\n\nIf you use this component just star it. A developer is more motivated to improve a project when there is some interest.\n\nOr consider offering me a coffee, it's a small thing but it is greatly appreciated: [about me](https://www.blocknot.es/about-me).\n\n## Contributors\n\n- [Mattia Roccoberton](https://blocknot.es/): author\n- The good guys that opened issues and pull requests from time to time\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n","funding_links":["https://github.com/sponsors/blocknotes"],"categories":["Ruby"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblocknotes%2Fadministrate_ransack","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fblocknotes%2Fadministrate_ransack","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblocknotes%2Fadministrate_ransack/lists"}