{"id":18513340,"url":"https://github.com/jbox-web/smart_listing","last_synced_at":"2025-10-31T19:30:37.258Z","repository":{"id":146101474,"uuid":"332930898","full_name":"jbox-web/smart_listing","owner":"jbox-web","description":"Ruby on Rails data listing gem with built-in sorting, filtering and in-place editing.","archived":false,"fork":false,"pushed_at":"2025-01-28T22:55:05.000Z","size":323,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-28T23:29:26.671Z","etag":null,"topics":[],"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/jbox-web.png","metadata":{"files":{"readme":"README.md","changelog":"Changes.md","contributing":null,"funding":null,"license":"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}},"created_at":"2021-01-26T01:06:44.000Z","updated_at":"2025-01-28T22:55:09.000Z","dependencies_parsed_at":"2023-05-14T15:00:20.467Z","dependency_job_id":"f92d0e07-c8c8-4c63-94e8-98aaadd0058d","html_url":"https://github.com/jbox-web/smart_listing","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jbox-web%2Fsmart_listing","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jbox-web%2Fsmart_listing/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jbox-web%2Fsmart_listing/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jbox-web%2Fsmart_listing/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jbox-web","download_url":"https://codeload.github.com/jbox-web/smart_listing/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239226414,"owners_count":19603260,"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":[],"created_at":"2024-11-06T15:37:44.864Z","updated_at":"2025-10-31T19:30:37.200Z","avatar_url":"https://github.com/jbox-web.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SmartListing\n\n[![GitHub license](https://img.shields.io/github/license/jbox-web/smart_listing.svg)](https://github.com/jbox-web/smart_listing/blob/master/LICENSE)\n[![GitHub release](https://img.shields.io/github/release/jbox-web/smart_listing.svg)](https://github.com/jbox-web/smart_listing/releases/latest)\n[![CI](https://github.com/jbox-web/smart_listing/workflows/CI/badge.svg)](https://github.com/jbox-web/smart_listing/actions)\n[![Code Climate](https://codeclimate.com/github/jbox-web/smart_listing/badges/gpa.svg)](https://codeclimate.com/github/jbox-web/smart_listing)\n[![Test Coverage](https://codeclimate.com/github/jbox-web/smart_listing/badges/coverage.svg)](https://codeclimate.com/github/jbox-web/smart_listing/coverage)\n\nSmartListing helps creating AJAX-enabled lists of ActiveRecord collections or arrays with pagination, filtering, sorting and in-place editing.\n\n[See it in action](http://showcase.sology.eu/smart_listing)\n\n## Installation\n\nAdd to your Gemfile:\n\n```ruby\ngem \"smart_listing\"\n```\n\nThen run:\n\n```sh\n$ bundle install\n```\n\nAlso, you need to add SmartListing to your asset pipeline:\n\n```\n//= require smart_listing\n```\n\n__Rails \u003e= 5.1 users__: Rails 5.1 has dropped jQuery dependency from the default stack in favour of `rails-ujs`. SmartListing still requires jQuery so make sure that you use `jquery_ujs` from `jquery-rails` gem and have following requires in your asset pipeline before `smart_listing`:\n```\n//= require jquery\n//= require jquery_ujs\n```\n\n### Initializer\n\nOptionally you can also install some configuration initializer:\n\n```sh\n$ rails generate smart_listing:install\n```\n\nIt will be placed in `config/initializers/smart_listing.rb` and will allow you to tweak some configuration settings like HTML classes and data attributes names.\n\n### Custom views\n\nSmartListing comes with some built-in views which are by default compatible with Bootstrap 3. You can easily change them after installing:\n\n```sh\n$ rails generate smart_listing:views\n```\n\nFiles will be placed in `app/views/smart_listing`.\n\n## Usage\n\nLet's start with a controller. In order to use SmartListing, in most cases you need to include controller extensions and SmartListing helper methods:\n\n```ruby\ninclude SmartListing::Helper::ControllerExtensions\nhelper  SmartListing::Helper\n```\n\nNext, put following code in controller action you desire:\n\n```ruby\n@users = smart_listing_create(:users, User.active, partial: \"users/listing\")\n```\n\nThis will create SmartListing named `:users` consisting of ActiveRecord scope `User.active` elements and rendered by partial `users/listing`. You can also use arrays instead of ActiveRecord collections. Just put `array: true` option just like for Pagy.\n\nIn the main view (typically something like `index.html.erb` or `index.html.haml`), use this method to render listing:\n\n```ruby\nsmart_listing_render(:users)\n```\n\n`smart_listing_render` does some magic and renders `users/listing` partial which may look like this (in HAML):\n\n```haml\n- unless smart_listing.empty?\n  %table\n    %thead\n      %tr\n        %th User name\n        %th Email\n    %tbody\n      - smart_listing.collection.each do |user|\n        %tr\n          %td= user.name\n          %td= user.email\n\n  = smart_listing.paginate\n- else\n  %p.warning No records!\n```\n\nYou can see that listing template has access to special `smart_listing` local variable which is basically an instance of `SmartListing::Helper::Builder`. It provides you with some helper methods that ease rendering of SmartListing:\n\n* `Builder#paginate` - renders Pagy pagination,\n* `Builder#pagination_per_page_links` - display some link that allow you to customize Pagy's `per_page`,\n* `Builder#collection` - accesses underlying list of items,\n* `Builder#empty?` - checks if collection is empty,\n* `Builder#count` - returns collection count,\n* `Builder#render` - basic template's `render` wrapper that automatically adds `smart_listing` local variable,\n\nThere are also other methods that will be described in detail below.\n\nIf you are using SmartListing with AJAX on (by default), one last thing required to make pagination (and other features) work is to create JS template for main view (typically something like `index.js.erb`):\n\n```erb\n\u003c%= smart_listing_update(:users) %\u003e\n```\n\n### Sorting\n\nSmartListing supports two modes of sorting: implicit and explicit. Implicit mode is enabled by default. In this mode, you define sort columns directly in the view:\n\n```haml\n- unless smart_listing.empty?\n  %table\n    %thead\n      %tr\n        %th= smart_listing.sortable \"User name\", :name\n        %th= smart_listing.sortable \"Email\", :email\n    %tbody\n      - smart_listing.collection.each do |user|\n        %tr\n          %td= user.name\n          %td= user.email\n\n  = smart_listing.paginate\n- else\n  %p.warning No records!\n```\n\nIn this case `:name` and `:email` are sorting column names. `Builder#sortable` renders special link containing column name and sort order (either `asc`, `desc`, or empty value).\n\nYou can also specify default sort order in the controller:\n\n```ruby\n@users = smart_listing_create(:users, User.active, partial: \"users/listing\", default_sort: {name: \"asc\"})\n```\n\nImplicit mode is convenient with simple data sets. In case you want to sort by joined column names, we advise you to use explicit sorting:\n```ruby\n@users = smart_listing_create :users, User.active.joins(:stats), partial: \"users/listing\",\n                              sort_attributes: [[:last_signin, \"stats.last_signin_at\"]],\n                              default_sort: {last_signin: \"desc\"}\n```\n\nNote that `:sort_attributes` are array which of course means, that order of attributes matters.\n\nThere's also a possibility to specify available sort directions using `:sort_dirs` option which is by default `[nil, \"asc\", \"desc\"]`.\n\n### List item management and in-place editing\n\nIn order to allow managing and editing list items, we need to reorganize our views a bit. Basically, each item needs to have its own partial:\n\n```haml\n- unless smart_listing.empty?\n  %table\n    %thead\n      %tr\n        %th= smart_listing.sortable \"User name\", \"name\"\n        %th= smart_listing.sortable \"Email\", \"email\"\n        %th\n    %tbody\n      - smart_listing.collection.each do |user|\n        %tr.editable{data: {id: user.id}}\n          = smart_listing.render partial: 'users/user', locals: {user: user}\n      = smart_listing.item_new colspan: 3, link: new_user_path\n\n  = smart_listing.paginate\n- else\n  %p.warning No records!\n```\n\n`\u003ctr\u003e` has now `editable` class and `data-id` attribute. These are essential to make it work. We've used also a new helper: `Builder#new_item`. It renders new row which is used for adding new items. `:link` needs to be valid url to new resource action which renders JS:\n\n```ruby\n\u003c%= smart_listing_item :users, :new, @new_user, \"users/form\" %\u003e\n```\n\nNote that `new` action does not need to create SmartListing (via `smart_listing_create`). It just initializes `@new_user` and renders JS view.\n\nNew partial for user (`users/user`) may look like this:\n```haml\n%td= user.name\n%td= user.email\n%td.actions= smart_listing_item_actions [{name: :show, url: user_path(user)}, {name: :edit, url: edit_user_path(user)}, {name: :destroy, url: user_path(user)}]\n```\n\n`smart_listing_item_actions` renders here links that allow to edit and destroy user item. `:show`, `:edit` and `:destroy` are built-in actions, you can also define your `:custom` actions. Again. `\u003ctd\u003e`'s class `actions` is important.\n\nController actions referenced by above urls are again plain Ruby on Rails actions that render JS like:\n\n```erb\n\u003c%= smart_listing_item :users, :new, @user, \"users/form\" %\u003e\n\u003c%= smart_listing_item :users, :edit, @user, \"users/form\" %\u003e\n\u003c%= smart_listing_item :users, :destroy, @user %\u003e\n```\n\nPartial name supplied to `smart_listing_item` (`users/form`) references `@user` as `object` and may look like this:\n\n```haml\n%td{colspan: 3}\n  - if object.persisted?\n    %p Edit user\n  - else\n    %p Add user\n\n  = form_for object, url: object.new_record? ? users_path : user_path(object), remote: true do |f|\n    %p\n      Name:\n      = f.text_field :name\n    %p\n      Email:\n      = f.text_field :email\n    %p= f.submit \"Save\"\n```\n\nAnd one last thing are `create` and `update` controller actions JS view:\n\n```ruby\n\u003c%= smart_listing_item :users, :create, @user, @user.persisted? ? \"users/user\" : \"users/form\" %\u003e\n\u003c%= smart_listing_item :users, :update, @user, @user.valid? ? \"users/user\" : \"users/form\" %\u003e\n```\n\n### Controls (filtering)\n\nSmartListing controls allow you to change somehow presented data. This is typically used for filtering records. Let's see how view with controls may look like:\n\n```haml\n= smart_listing_controls_for(:users) do\n  .filter.input-append\n    = text_field_tag :filter, '', class: \"search\", placeholder: \"Type name here\", autocomplete: \"off\"\n    %button.btn.disabled{type: \"submit\"}\n      %span.glyphicon.glyphicon-search\n```\n\nThis gives you nice Bootstrap-enabled filter field with keychange handler. Of course you can use any other form fields in controls too.\n\nWhen form field changes its value, form is submitted and request is made. This needs to be handled in controller:\n\n```ruby\nusers_scope = User.active.joins(:stats)\nusers_scope = users_scope.like(params[:filter]) if params[:filter]\n@users = smart_listing_create :users, users_scope, partial: \"users/listing\"\n```\n\nThen, JS view is rendered and your SmartListing updated. That's it!\n\n### Simplified views\n\nYou don't need to create all the JS views in case you want to simply use one SmartListing per controller. Just use helper methods without their first attribute (name) ie. `smart_listing_create(User.active, partial: \"users/listing\")`. Then define two helper methods:\n\n * `smart_listing_resource` returning single object,\n * `smart_listing_collection` returning collection of objects.\n\nSmartListing default views will user these methods to render your list properly.\n\n### More customization\n\nApart from standard SmartListing initializer, you can also define custom config profiles. In order to do this, use following syntax:\n\n```ruby\nSmartListing.configure(:awesome_profile) do |config|\n  # put your definitions here\nend\n```\n\nIn order to use this profile, create helper method named `smart_listing_config_profile` returning profile name and put into your JS `SmartListing.config.merge()` function call. `merge()` function expects parameter with config attributes hash or reads body data-attribute named `smart-listing-config`. Hash of config attributes can be obtained by using helper method `SmartListing.config(:awesome_profile).to_json`.\n\n## Not enough?\n\nFor more information and some use cases, see the [Showcase](http://showcase.sology.eu/smart_listing)\n\n## Credits\n\nSmartListing uses great pagination gem Pagy https://github.com/ddnexus/pagy\n\nCreated by Sology http://www.sology.eu\n\nInitial development sponsored by Smart Language Apps Limited http://smartlanguageapps.com/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjbox-web%2Fsmart_listing","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjbox-web%2Fsmart_listing","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjbox-web%2Fsmart_listing/lists"}