{"id":22604684,"url":"https://github.com/michaelwapp/dynamic_search","last_synced_at":"2026-04-28T21:31:18.166Z","repository":{"id":265337880,"uuid":"748940710","full_name":"michaelwapp/dynamic_search","owner":"michaelwapp","description":"An example implementation about how to implement a dynamic search bar using TurboFrames in Rails 7","archived":false,"fork":false,"pushed_at":"2024-01-27T05:15:29.000Z","size":51,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-28T07:39:29.641Z","etag":null,"topics":["dynamic-search","hotwire-turbo","rails","software","turbo"],"latest_commit_sha":null,"homepage":"https://michaelwapp.com","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/michaelwapp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2024-01-27T05:15:12.000Z","updated_at":"2024-01-27T05:16:06.000Z","dependencies_parsed_at":"2024-11-29T02:15:15.697Z","dependency_job_id":null,"html_url":"https://github.com/michaelwapp/dynamic_search","commit_stats":null,"previous_names":["michaelwapp/dynamic_search"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/michaelwapp/dynamic_search","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michaelwapp%2Fdynamic_search","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michaelwapp%2Fdynamic_search/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michaelwapp%2Fdynamic_search/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michaelwapp%2Fdynamic_search/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/michaelwapp","download_url":"https://codeload.github.com/michaelwapp/dynamic_search/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michaelwapp%2Fdynamic_search/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32400797,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-28T19:38:08.556Z","status":"ssl_error","status_checked_at":"2026-04-28T19:37:55.688Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["dynamic-search","hotwire-turbo","rails","software","turbo"],"created_at":"2024-12-08T13:10:18.463Z","updated_at":"2026-04-28T21:31:18.130Z","avatar_url":"https://github.com/michaelwapp.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# Dynamic Search Implementation using Turbo Frames\n\nThis Rails 7.1 project showcases how to implement dynamic search (searching in you local data as well as from an external data source) functionality using Turbo Frames. The project is built using Ruby 3.2.2 and leverages the power of Hotwire's TurboFrames to update parts of the webpage without a full page reload.\n\n## Prerequisites\n\nBefore you begin, ensure you have the following installed:\n- Ruby 3.2.2\n- Rails 7.1\n- Node.js and Yarn (for JavaScript dependencies)\n- Bootstrap 5.3.x\n\n## Getting Started\n\nTo get started with the project, clone the repository and install the necessary dependencies:\n\n```bash\nbundle install\nyarn install\n```\n\n## Running the Application\n\nTo run the application locally:\n\n```bash\nbin/dev\n```\n\nNavigate to `http://localhost:3000` in your web browser to view the application.\n\n## Dynamic Search Form with TurboFrames\n\nThe application demonstrates how to use TurboFrames to dynamically load and display search results from a search form. Here's an overview of the implementation:\n\n### 1. Setup TurboFrames\n\nEnsure that Turbo is included in your application. You can verify this in your `Gemfile` and `app/javascript/application.js`.\n\n### 2. Create a search form\n\nCreate a search form in any view (e.g., `app/views/index.html.erb`) and ensure the form submits against the same action.\n\n```html \n\u003c%= form_with url: projects_path, method: :get, data: { controller: \"formsubmission\", turbo_frame: 'project_listings' } do |form| %\u003e\n    \u003c%= form.search_field :q, class: 'form-control', placeholder: \"Search for Name or Description\", data: { action: \"input-\u003eformsubmission#search\" } %\u003e\n\u003c% end %\u003e\n```\n\n### 3. Use TurboFrame to Display the search results\n\nUse a TurboFrame tag to define the area where the search results will be displayed. Use another TurboFrame tag to display the external search results. This turbo frame is lazy loaded meaning that as soon as it is displayed it triggers it's defined action. This allows us to trigger the external search query in a different controller action. The search value and a way to only trigger the external search is passed s.t. we can avoid searching in the external search for empty search values or in case the local search already has some results. \n\n```erb\n\u003c%= turbo_frame_tag 'project_listings' do %\u003e\n    \u003c% unless @results.empty? %\u003e\n        \u003c% @results\u0026.each do |project| %\u003e\n            \u003cdiv class=\"p-2 border\"\u003e\n                \u003cdiv class=\"fs-6\"\u003eName: \u003c%= project.name %\u003e - Description: \u003c%= project.description %\u003e\u003c/div\u003e\n            \u003c/div\u003e\n        \u003c% end %\u003e\n    \u003c% end %\u003e\n    \u003c%= turbo_frame_tag 'external_search_result', src: load_external_search_project_path(q: @search, avoid_search: @results.any?), loading: :lazy do %\u003e\n    \u003c% end %\u003e\n\u003c% end %\u003e\n```\n\nAs the `external_search_result` TurboFrame is added within the main search result TurboFrame `proejct_listings` it's always updated on every search result and therefore automatically triggers an external search in case no local search results are available.\n\n### 4. Add External Search Action\n\nThe external search action added to our controller looks like the following code block. It demonstrates how an external search could look like. \n\n```ruby\n  def external_search_project\n    return if params[:q].blank? || params[:avoid_search] == \"true\"\n\n    sleep 1.0 # simulate external request\n    @external_search_result = [Project.new(name: \"External Project\", description: \"Loaded from wherever\")]\n  end\n```\n\nThis action returns a view template with the same `external_search_result` TurboFrame s.t. it will only update the external search results in the view. \n\n```html \n\u003c%= turbo_frame_tag \"external_search_result\" do %\u003e\n  \u003c% @external_search_result\u0026.each do |project| %\u003e\n    \u003cdiv class=\"p-2 border\"\u003e\n      \u003cdiv class=\"fs-6\"\u003eName: \u003c%= project.name %\u003e - Description: \u003c%= project.description %\u003e\u003c/div\u003e\n    \u003c/div\u003e\n  \u003c% end %\u003e\n\u003c% end %\u003e\n\n```\n\nNow, in case no local search results are provided, the external search is triggered and the results are shown in the corresponding TurboFrame.\n\n### 5. Optional: Automatic Form Submission\n\nIn order to have the search form submit automattically, I've added a simple Stimulus controller which auto submits the form after 300ms. The implementation looks like this: \n\n```javascript\nimport { Controller } from \"@hotwired/stimulus\"\n\nexport default class extends Controller {\n\n  search() {\n    console.log(\"Search Submit\")\n    clearTimeout(this.timeout)\n    this.timeout = setTimeout(() =\u003e {\n      this.element.requestSubmit()\n    }, 300)\n  }\n}\n```\n\n## Further Information\n\nFor more information on TurboFrames, refer to the following resources:\n- [Hotwire Turbo](https://turbo.hotwired.dev/)\n\n### Contact\n\nFor more details, contact [me](michaelwapp.com)\n\nCopyright Michael Bauer-Wapp 2024\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmichaelwapp%2Fdynamic_search","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmichaelwapp%2Fdynamic_search","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmichaelwapp%2Fdynamic_search/lists"}