{"id":13411859,"url":"https://github.com/nikolalsvk/render_async","last_synced_at":"2025-10-08T18:01:16.005Z","repository":{"id":46672404,"uuid":"85574729","full_name":"nikolalsvk/render_async","owner":"nikolalsvk","description":"render_async lets you include pages asynchronously with AJAX","archived":false,"fork":false,"pushed_at":"2024-11-11T17:59:10.000Z","size":612,"stargazers_count":1081,"open_issues_count":13,"forks_count":74,"subscribers_count":19,"default_branch":"master","last_synced_at":"2025-10-02T13:30:03.105Z","etag":null,"topics":["ajax","async","gem","hacktoberfest","rails","rails5","semaphore-open-source"],"latest_commit_sha":null,"homepage":"https://rubygems.org/gems/render_async/","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/nikolalsvk.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":".github/FUNDING.yml","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},"funding":{"github":"nikolalsvk","tidelift":"rubygems/render_async","custom":"https://www.paypal.me/nikolalsvk/10"}},"created_at":"2017-03-20T12:34:17.000Z","updated_at":"2025-08-27T12:12:07.000Z","dependencies_parsed_at":"2024-01-08T18:03:38.275Z","dependency_job_id":"e70b29df-578c-482c-95e2-97922b65db94","html_url":"https://github.com/nikolalsvk/render_async","commit_stats":{"total_commits":269,"total_committers":25,"mean_commits":10.76,"dds":0.2639405204460966,"last_synced_commit":"c2ac631554b2fc5f44f0d56580a810ee3d2bdfbc"},"previous_names":[],"tags_count":30,"template":false,"template_full_name":null,"purl":"pkg:github/nikolalsvk/render_async","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikolalsvk%2Frender_async","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikolalsvk%2Frender_async/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikolalsvk%2Frender_async/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikolalsvk%2Frender_async/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nikolalsvk","download_url":"https://codeload.github.com/nikolalsvk/render_async/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikolalsvk%2Frender_async/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278888956,"owners_count":26063478,"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","status":"online","status_checked_at":"2025-10-08T02:00:06.501Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["ajax","async","gem","hacktoberfest","rails","rails5","semaphore-open-source"],"created_at":"2024-07-30T20:01:17.697Z","updated_at":"2025-10-08T18:01:15.981Z","avatar_url":"https://github.com/nikolalsvk.png","language":"Ruby","funding_links":["https://github.com/sponsors/nikolalsvk","https://tidelift.com/funding/github/rubygems/render_async","https://www.paypal.me/nikolalsvk/10"],"categories":["Ruby"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src='./cover.png' alt='render_async' /\u003e\n\n  \u003ch1 align=\"center\"\u003e👋 Welcome to render_async\u003c/h1\u003e\n\n  \u003ch3 align=\"center\"\u003eLet's make your Rails pages fast again :racehorse:\u003c/h3\u003e\n\n  \u003cbr /\u003e\n\n  \u003cp align=\"center\"\u003e\n    \u003ca href=\"https://www.paypal.me/nikolalsvk/10\" target=\"_blank\"\u003e\n     \u003cimg src=\"https://img.shields.io/badge/$-support-green.svg\" alt=\"Donate\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://rubygems.org/gems/render_async\" target=\"_blank\"\u003e\n      \u003cimg src=\"https://img.shields.io/gem/dt/render_async\" alt=\"Downloads\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"#contributors\" target=\"_blank\"\u003e\n     \u003cimg src=\"https://img.shields.io/github/all-contributors/renderedtext/render_async\" alt=\"All contributors\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://badge.fury.io/rb/render_async\" target=\"_blank\"\u003e\n     \u003cimg src=\"https://badge.fury.io/rb/render_async.svg\" alt=\"Gem Version\" /\u003e\n    \u003c/a\u003e\n    \u003cbr /\u003e\n    \u003ca href=\"https://discord.gg/SPfbeRm\" target=\"_blank\"\u003e\n      \u003cimg src=\"https://img.shields.io/discord/738783603214909521\" alt=\"Discord Server\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://codeclimate.com/github/renderedtext/render_async\" target=\"_blank\"\u003e\n     \u003cimg src=\"https://img.shields.io/codeclimate/maintainability/renderedtext/render_async\" alt=\"Code Climate Maintainablity\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://codeclimate.com/github/renderedtext/render_async/coverage\" target=\"_blank\"\u003e\n     \u003cimg src=\"https://img.shields.io/codeclimate/coverage/renderedtext/render_async\" alt=\"Test Coverage\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/renderedtext/render_async/blob/master/LICENSE\" target=\"_blank\"\u003e\n      \u003cimg src=\"https://img.shields.io/github/license/renderedtext/render_async\" alt=\"License\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://www.codetriage.com/renderedtext/render_async\" target=\"_blank\"\u003e\n     \u003cimg src=\"https://www.codetriage.com/renderedtext/render_async/badges/users.svg\" alt=\"Help Contribute to Open Source\" /\u003e\n    \u003c/a\u003e\n  \u003c/p\u003e\n\u003c/p\u003e\n\n### `render_async` is here to make your pages show faster to users.\n\nPages become faster seamlessly by rendering partials to your views.\n\nPartials render **asynchronously** and let users see your page **faster**\nthan using regular rendering.\n\nIt works with Rails and its tools out of the box.\n\n:sparkles:  A quick overview of how `render_async` does its magic:\n\n1. user visits a page\n2. `render_async` makes an AJAX request on the controller action\n3. controller renders a partial\n4. partial renders in the place where you put `render_async` view helper\n\nJavaScript is injected straight into `\u003c%= content_for :render_async %\u003e` so you choose\nwhere to put it.\n\n:mega:  P.S. Join our [Discord channel](https://discord.gg/SPfbeRm) for help and discussion, and let's make `render_async` even better!\n\n## :package: Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'render_async'\n```\n\nAnd then execute:\n\n    $ bundle install\n\n## :hammer: Usage\n\n1. Include `render_async` view helper somewhere in your views (e.g. `app/views/comments/show.html.erb`):\n    ```erb\n    \u003c%= render_async comment_stats_path %\u003e\n    ```\n\n2. Then create a route for it `config/routes.rb`:\n    ```ruby\n    get :comment_stats, controller: :comments\n    ```\n\n3. Fill in the logic in your controller (e.g. `app/controllers/comments_controller.rb`):\n    ```ruby\n    def comment_stats\n      @stats = Comment.get_stats\n\n      render partial: \"comment_stats\"\n    end\n    ```\n\n4. Create a partial that will render (e.g. `app/views/comments/_comment_stats.html.erb`):\n    ```erb\n    \u003cdiv class=\"col-md-6\"\u003e\n      \u003c%= @stats %\u003e\n    \u003c/div\u003e\n    ```\n\n5. Add `content_for` in your base view file in the body part (e.g. `app/views/layouts/application.html.erb`):\n    ```erb\n    \u003c%= content_for :render_async %\u003e\n    ```\n\n## :hammer_and_wrench: Advanced usage\n\nAdvanced usage includes information on different options, such as:\n\n  - [Passing in a container ID](#passing-in-a-container-id)\n  - [Passing in a container class name](#passing-in-a-container-class-name)\n  - [Passing in HTML options](#passing-in-html-options)\n  - [Passing in an HTML element name](#passing-in-an-html-element-name)\n  - [Passing in a placeholder](#passing-in-a-placeholder)\n  - [Passing in an event name](#passing-in-an-event-name)\n  - [Using default events](#using-default-events)\n  - [Refreshing the partial](#refreshing-the-partial)\n  - [Retry on failure](#retry-on-failure)\n    - [Retry after some time](#retry-after-some-time)\n  - [Toggle event](#toggle-event)\n    - [Control polling with a toggle](#control-polling-with-a-toggle)\n  - [Polling](#polling)\n  - [Controlled polling](#controlled-polling)\n  - [Handling errors](#handling-errors)\n  - [Caching](#caching)\n  - [Doing non-GET requests](#doing-non-get-requests)\n  - [Using with Turbolinks](#using-with-turbolinks)\n  - [Using with Turbo](#using-with-turbo)\n  - [Using with respond_to and JS format](#using-with-respond_to-and-js-format)\n  - [Nested async renders](#nested-async-renders)\n  - [Customizing the content_for name](#customizing-the-content_for-name)\n  - [Configuration options](#configuration-options)\n\n### Passing in a container ID\n\n`render_async` renders an element that gets replaced with the content\nof your request response. In order to have more control over the element\nthat renders first (before the request), you can set the ID of that element.\n\nTo set ID of the container element, you can do the following:\n```erb\n\u003c%= render_async users_path, container_id: 'users-container' %\u003e\n```\n\nRendered code in the view:\n```html\n\u003cdiv id=\"users-container\"\u003e\n\u003c/div\u003e\n\n...\n```\n\n### Passing in a container class name\n\n`render_async` renders an element that gets replaced with the content of your\nrequest response. If you want to style that element, you can set the class name\non it.\n\n```erb\n\u003c%= render_async users_path, container_class: 'users-container-class' %\u003e\n```\n\nRendered code in the view:\n```html\n\u003cdiv id=\"render_async_18b8a6cd161499117471\" class=\"users-container-class\"\u003e\n\u003c/div\u003e\n\n...\n```\n\n### Passing in HTML options\n\n`render_async` can accept `html_options` as a hash.\n`html_options` is an optional hash that gets passed to a Rails'\n`javascript_tag`, to drop HTML tags into the `script` element.\n\nExample of utilizing `html_options` with a [nonce](https://edgeguides.rubyonrails.org/security.html#content-security-policy):\n\n```erb\n\u003c%= render_async users_path, html_options: { nonce: true } %\u003e\n```\n\nRendered code in the view:\n```html\n\u003cscript nonce=\"2x012CYGxKgM8qAApxRHxA==\"\u003e\n//\u003c![CDATA[\n  ...\n//]]\u003e\n\u003c/script\u003e\n\n...\n\n\u003cdiv id=\"render_async_18b8a6cd161499117471\" class=\"\"\u003e\n\u003c/div\u003e\n```\n\n\u003e :bulb:  You can enable `nonce` to be set everywhere by using [configuration option](#configuration-options) render_async provides.\n\n### Passing in an HTML element name\n\n`render_async` can take in an HTML element name, allowing you to control\nwhat type of container gets rendered. This can be useful when you're using\n[`render_async` inside a table](https://github.com/renderedtext/render_async/issues/12)\nand you need it to render a `tr` element before your request gets loaded, so\nyour content doesn't get pushed out of the table.\n\nExample of using HTML element name:\n```erb\n\u003c%= render_async users_path, html_element_name: 'tr' %\u003e\n```\n\nRendered code in the view:\n```html\n\u003ctr id=\"render_async_04229e7abe1507987376\"\u003e\n\u003c/tr\u003e\n...\n```\n\n### Passing in a placeholder\n\n`render_async` can be called with a block that will act as a placeholder before\nyour AJAX call finishes.\n\nExample of passing in a block:\n\n```erb\n\u003c%= render_async users_path do %\u003e\n  \u003ch1\u003eUsers are loading...\u003c/h1\u003e\n\u003c% end %\u003e\n```\n\nRendered code in the view:\n```html\n\u003cdiv id=\"render_async_14d7ac165d1505993721\"\u003e\n  \u003ch1\u003eUsers are loading...\u003c/h1\u003e\n\u003c/div\u003e\n\n\u003cscript\u003e\n//\u003c![CDATA[\n  ...\n//]]\u003e\n\u003c/script\u003e\n```\n\nAfter AJAX is finished, placeholder will be replaced with the request's\nresponse.\n\n### Passing in an event name\n\n`render_async` can receive `:event_name` option which will emit JavaScript\nevent after it's done with fetching and rendering request content to HTML.\n\nThis can be useful to have if you want to add some JavaScript functionality\nafter your partial is loaded through `render_async`.\n\nYou can also access the associated container (DOM node) in the event object\nthat gets emitted.\n\nExample of passing it to `render_async`:\n```erb\n\u003c%= render_async users_path, event_name: \"users-loaded\" %\u003e\n```\n\nRendered code in view:\n```html\n\u003cdiv id=\"render_async_04229e7abe1507987376\"\u003e\n\u003c/div\u003e\n\n\u003cscript\u003e\n//\u003c![CDATA[\n  ...\n    document.dispatchEvent(new Event(\"users-loaded\"));\n  ...\n//]]\u003e\n\u003c/script\u003e\n```\n\nThen, in your JavaScript code, you could do something like this:\n```javascript\ndocument.addEventListener(\"users-loaded\", function(event) {\n  console.log(\"Users have loaded!\", event.container); // Access the container which loaded the users\n});\n```\n\n\u003e :bulb: Dispatching events is also supported for older browsers that don't support Event constructor.\n\n### Using default events\n\n`render_async` will fire the event `render_async_load` when an async partial\nhas loaded and rendered on the page.\n\nIn case there is an error, the event `render_async_error` will fire instead.\n\nThis event will fire for all `render_async` partials on the page. For every\nevent, the associated container (DOM node) will be passed along.\n\nThis can be useful to apply JavaScript to content loaded after the page is\nready.\n\nExample of using events:\n\n```js\n// Vanilla javascript\ndocument.addEventListener('render_async_load', function(event) {\n  console.log('Async partial loaded in this container:', event.container);\n});\ndocument.addEventListener('render_async_error', function(event) {\n  console.log('Async partial could not load in this container:', event.container);\n});\n\n// with jQuery\n$(document).on('render_async_load', function(event) {\n  console.log('Async partial loaded in this container:', event.container);\n});\n$(document).on('render_async_error', function(event) {\n  console.log('Async partial could not load in this container:', event.container);\n});\n```\n\n### Refreshing the partial\n\n`render_async` lets you refresh (reload) the partial by letting you dispatch\nthe 'refresh' event on the `render_async`'s container. An example:\n\n```erb\n\u003c%= render_async comments_path,\n                 container_id: 'refresh-me',\n                 replace_container: false %\u003e\n\n\u003cbutton id=\"refresh-button\"\u003eRefresh comments\u003c/button\u003e\n\n\u003cscript\u003e\n  var button = document.getElementById('refresh-button')\n  var container = document.getElementById('refresh-me');\n\n  button.addEventListener('click', function() {\n    var event = new Event('refresh');\n\n    // Dispatch 'refresh' on the render_async container\n    container.dispatchEvent(event)\n  })\n\u003c/script\u003e\n```\n\nIf you follow the example above, when you click \"Refresh comments\" button,\n`render_async` will trigger again and reload the `comments_path`.\n\n\u003e :bulb:  Note that you need to pass `replace_container: false` so you can later dispatch an event on that container.\n\n### Retry on failure\n\n`render_async` can retry your requests if they fail for some reason.\n\nIf you want `render_async` to retry a request for number of times, you can do\nthis:\n```erb\n\u003c%= render_async users_path, retry_count: 5, error_message: \"Couldn't fetch it\" %\u003e\n```\n\nNow render_async will retry `users_path` for 5 times. If it succeeds in\nbetween, it will stop with dispatching requests. If it fails after 5 times,\nit will show an [error message](#handling-errors) which you need to specify.\n\nThis can show useful when you know your requests often fail, and you don't want\nto refresh the whole page just to retry them.\n\n#### Retry after some time\n\nIf you want to retry requests but with some delay in between the calls, you can\npass a `retry_delay` option together with `retry_count` like so:\n\n```erb\n\u003c%= render_async users_path,\n                 retry_count: 5,\n                 retry_delay: 2000 %\u003e\n```\n\nThis will make `render_async` wait for 2 seconds before retrying after each\nfailure. In the end, if the request is still failing after 5th time, it will\ndispatch a [default error event](#using-default-events).\n\n\u003e :candy:  If you are catching an event after an error, you can get `retryCount` from\nthe event. `retryCount` will have the number of retries it took before the event was dispatched.\n\nHere is an example on how to get `retryCount`:\n\n```erb\n\u003c%= render_async users_path,\n                 retry_count: 5,\n                 retry_delay: 2000,\n                 error_event_name: 'it-failed-badly' %\u003e\n\n\u003cscript\u003e\n  document.addEventListener('it-failed-badly', function(event) {\n    console.log(\"Request failed after \" + event.retryCount + \" tries!\")\n  });\n\u003c/script\u003e\n```\n\nIf you need to pass retry count to the backend, you can pass `retry_count_header` in `render_async`'s options:\n\n```erb\n\u003c%= render_async users_path,\n                 retry_count: 5,\n                 retry_count_header: 'Retry-Count-Current' %\u003e\n```\n\nAnd then in controller you can read the value from request headers.\n\n```\nrequest.headers['Retry-Count-Current']\u0026.to_i\n```\n\n### Toggle event\n\nYou can trigger `render_async` loading by clicking or doing another event to a\ncertain HTML element. You can do this by passing in a selector and an event\nname which will trigger `render_async`. If you don't specify an event name, the\ndefault event that will trigger `render_async` will be 'click' event. You can\ndo this by doing the following:\n\n```erb\n\u003ca href='#' id='comments-button'\u003eLoad comments\u003c/a\u003e\n\u003c%= render_async comments_path, toggle: { selector: '#comments-button', event: :click } %\u003e\n```\n\nThis will trigger `render_async` to load the `comments_path` when you click the `#comments-button` element.\nIf you want to remove an event once it's triggered, you can pass `once: true` in the toggle options.\nThe `once` option is false (`nil`) by default.\n\nYou can also pass in a placeholder before the `render_async` is triggered. That\nway, the element that started `render_async` logic will be removed after the\nrequest has been completed. You can achieve this behaviour with something like this:\n\n```erb\n\u003c%= render_async comments_path, toggle: { selector: '#comments-button', event: :click } do %\u003e\n  \u003ca href='#' id='comments-button'\u003eLoad comments\u003c/a\u003e\n\u003c% end %\u003e\n```\n\n#### Control polling with a toggle\n\nAlso, you can mix interval and toggle features. This way, you can turn polling\non, and off by clicking the \"Load comments\" button. In order to do this, you need to\npass `toggle` and `interval` arguments to `render_async` call like this:\n\n```erb\n\u003ca href='#' id='comments-button'\u003eLoad comments\u003c/a\u003e\n\u003c%= render_async comments_path, toggle: { selector: '#comments-button', event: :click }, interval: 2000 %\u003e\n```\n\nIf you want `render_async` to render the request on load, you can pass `start:\ntrue`. Passing the `start` option inside the `toggle` hash will trigger\n`render_async` on page load. You can then toggle off polling by interacting\nwith the element you specified. An example:\n\n```erb\n\u003ca href='#' id='comments-button'\u003eToggle comments loading\u003c/a\u003e\n\u003c%= render_async comments_path,\n                 toggle: { selector: '#comments-button',\n                           event: :click,\n                           start: true },\n                 interval: 2000 %\u003e\n```\n\nIn the example above, the comments will load as soon as the page is rendered.\nThen, you can stop polling for comments by clicking the \"Toggle comments\nloading\" button.\n\n### Polling\n\nYou can call `render_async` with interval argument. This will make render_async\ncall specified path at the specified interval.\n\nBy doing this:\n```erb\n\u003c%= render_async comments_path, interval: 5000 %\u003e\n```\nYou are telling `render_async` to fetch comments_path every 5 seconds.\n\nThis can be handy if you want to enable polling for a specific URL.\n\n\u003e :warning:  By passing interval to `render_async`, the initial container element\n\u003e will remain in the HTML tree and it will not be replaced with request response.\n\u003e You can handle how that container element is rendered and its style by\n\u003e [passing in an HTML element name](#passing-in-an-html-element-name) and\n\u003e [HTML element class](#passing-in-a-container-class-name).\n\n### Controlled polling\n\nYou can controller `render_async` [polling](#polling) in 2 manners.\nFirst one is pretty simple, and it involves using the [toggle](#toggle-event)\nfeature. To do this, you can follow instructions in the\n[control polling with a toggle section](#control-polling-with-a-toggle).\n\nThe second option is more advanced and it involves emitting events to the `render_async`'s\ncontainer element. From your code, you can emit the following events:\n  - 'async-stop' - this will stop polling\n  - 'async-start' - this will start polling.\n\n\u003e :bulb:  Please note that events need to be dispatched to a render_async container.\n\nAn example of how you can do this looks like this:\n\n```erb\n\u003c%= render_async wave_render_async_path,\n                 container_id: 'controllable-interval', # set container_id so we can get it later easily\n                 interval: 3000 %\u003e\n\n\u003cbutton id='stop-polling'\u003eStop polling\u003c/button\u003e\n\u003cbutton id='start-polling'\u003eStart polling\u003c/button\u003e\n\n\u003cscript\u003e\n  var container = document.getElementById('controllable-interval')\n  var stopPolling = document.getElementById('stop-polling')\n  var startPolling = document.getElementById('start-polling')\n\n  var triggerEventOnContainer = function(eventName) {\n    var event = new Event(eventName);\n\n    container.dispatchEvent(event)\n  }\n\n  stopPolling.addEventListener('click', function() {\n    container.innerHTML = '\u003cp\u003ePolling stopped\u003c/p\u003e'\n    triggerEventOnContainer('async-stop')\n  })\n  startPolling.addEventListener('click', function() {\n    triggerEventOnContainer('async-start')\n  })\n\u003c/script\u003e\n```\n\nWe are rendering two buttons - \"Stop polling\" and \"Start polling\". Then, we\nattach an event listener to catch any clicking on the buttons. When the buttons\nare clicked, we either stop the polling or start the polling, depending on which\nbutton a user clicks.\n\n### Handling errors\n\n`render_async` lets you handle errors by allowing you to pass in `error_message`\nand `error_event_name`.\n\n- `error_message`\n\n  passing an `error_message` will render a message if the AJAX requests fails for\n  some reason\n  ```erb\n  \u003c%= render_async users_path,\n                   error_message: '\u003cp\u003eSorry, users loading went wrong :(\u003c/p\u003e' %\u003e\n  ```\n\n- `error_event_name`\n\n  calling `render_async` with `error_event_name` will dispatch event in the case\n  of an error with your AJAX call.\n  ```erb\n  \u003c%= render_asyc users_path, error_event_name: 'users-error-event' %\u003e\n  ```\n\n  You can then catch the event in your code with:\n  ```js\n  document.addEventListener('users-error-event', function() {\n    // I'm on it\n  })\n  ```\n\n### Caching\n\n`render_async` can utilize view fragment caching to avoid extra AJAX calls.\n\nIn your views (e.g. `app/views/comments/show.html.erb`):\n```erb\n# note 'render_async_cache' instead of standard 'render_async'\n\u003c%= render_async_cache comment_stats_path %\u003e\n```\n\nThen, in the partial (e.g. `app/views/comments/_comment_stats.html.erb`):\n```erb\n\u003c% cache render_async_cache_key(request.path), skip_digest: true do %\u003e\n  \u003cdiv class=\"col-md-6\"\u003e\n    \u003c%= @stats %\u003e\n  \u003c/div\u003e\n\u003c% end %\u003e\n```\n\n- The first time the page renders, it will make the AJAX call.\n- Any other times (until the cache expires), it will render from cache\n  instantly, without making the AJAX call.\n- You can expire cache simply by passing `:expires_in` in your view where\n  you cache the partial\n\n### Doing non-GET requests\n\nBy default, `render_async` creates AJAX GET requests for the path you provide.\nIf you want to change this behaviour, you can pass in a `method` argument to\n`render_async` view helper.\n\n```erb\n\u003c%= render_async users_path, method: 'POST' %\u003e\n```\n\nYou can also set `body` and `headers` of the request if you need them.\n\n```erb\n\u003c%= render_async users_path,\n                 method: 'POST',\n                 data: { fresh: 'AF' },\n                 headers: { 'Content-Type': 'text' } %\u003e\n```\n\n### Using with Turbolinks\n\nOn Turbolinks applications, you may experience caching issues when navigating\naway from, and then back to, a page with a `render_async` call on it. This will\nlikely show up as an empty div.\n\nIf you're using Turbolinks 5 or higher, you can resolve this by setting Turbolinks\nconfiguration of `render_async` to true:\n\n```rb\nRenderAsync.configure do |config|\n  config.turbolinks = true # Enable this option if you are using Turbolinks 5+\nend\n```\n\nThis way, you're not breaking Turbolinks flow of loading or reloading a page.\nIt is more efficient than the next option below.\n\nAnother option:\nIf you want, you can tell Turbolinks to reload your `render_async` call as follows:\n\n```erb\n\u003c%= render_async events_path, html_options: { 'data-turbolinks-track': 'reload' } %\u003e\n```\n\nThis will reload the whole page with Turbolinks.\n\n\u003e :bulb:  If Turbolinks is misbehaving in some way, make sure to put `\u003c%= content_for :render_async %\u003e` in your base view file in\nthe `\u003cbody\u003e` and not the `\u003chead\u003e`.\n\n### Using with Turbo\n\nOn Turbo applications, you may experience caching issues when navigating\naway from, and then back to, a page with a `render_async` call on it. This will\nlikely show up as an empty div.\n\nIf you're using Turbo, you can resolve this by setting Turbo\nconfiguration of `render_async` to true:\n\n```rb\nRenderAsync.configure do |config|\n  config.turbo = true # Enable this option if you are using Turbo\nend\n```\n\nThis way, you're not breaking Turbos flow of loading or reloading a page.\nIt is more efficient than the next option below.\n\nAnother option:\nIf you want, you can tell Turbo to reload your `render_async` call as follows:\n\n```erb\n\u003c%= render_async events_path, html_options: { 'data-turbo-track': 'reload' } %\u003e\n```\n\nThis will reload the whole page with Turbo.\n\n\u003e :bulb:  If Turbo is misbehaving in some way, make sure to put `\u003c%= content_for :render_async %\u003e` in your base view file in\nthe `\u003cbody\u003e` and not the `\u003chead\u003e`.\n\n### Using with respond_to and JS format\n\nIf you need to restrict the action to only respond to AJAX requests, you'll\nlikely wrap it inside `respond_to`/`format.js` blocks like this:\n\n```ruby\ndef comment_stats\n  respond_to do |format|\n    format.js do\n      @stats = Comment.get_stats\n\n      render partial: \"comment_stats\"\n    end\n  end\nend\n```\n\nWhen you do this, Rails will sometimes set the response's `Content-Type` header\nto `text/javascript`. This causes the partial not to be rendered in the HTML.\nThis usually happens when there's browser caching.\n\nYou can get around it by specifying the content type to `text/html` in the\nrender call:\n\n```ruby\nrender partial: \"comment_stats\", content_type: 'text/html'\n```\n\n### Nested async renders\n\nIt is possible to nest async templates within other async templates. When doing\nso, another `content_for` is required to ensure the JavaScript needed to load\nnested templates is included.\n\nFor example:\n```erb\n\u003c%# app/views/comments/show.html.erb %\u003e\n\n\u003c%= render_async comment_stats_path %\u003e\n```\n\n```erb\n\u003c%# app/views/comments/_comment_stats.html.erb %\u003e\n\n\u003cdiv class=\"col-md-6\"\u003e\n  \u003c%= @stats %\u003e\n\u003c/div\u003e\n\n\u003cdiv class=\"col-md-6\"\u003e\n  \u003c%= render_async comment_advanced_stats_path %\u003e\n\u003c/div\u003e\n\n\u003c%= content_for :render_async %\u003e\n```\n\n### Customizing the content_for name\n\nThe `content_for` name may be customized by passing the `content_for_name`\noption to `render_async`. This option is especially useful when doing [nested async\nrenders](#nested-async-renders) to better control the location of the injected JavaScript.\n\nFor example:\n```erb\n\u003c%= render_async comment_stats_path, content_for_name: :render_async_comment_stats %\u003e\n\n\u003c%= content_for :render_async_comment_stats %\u003e\n```\n\n### Configuration options\n\n`render_async` renders Vanilla JS (regular JavaScript, non-jQuery code)\n**by default** in order to fetch the request from the server.\n\nIf you want `render_async` to use jQuery code, you need to configure it to do\nso.\n\nYou can configure it by doing the following anywhere before you call\n`render_async`:\n\n```rb\nRenderAsync.configure do |config|\n  config.jquery = true # This will render jQuery code, and skip Vanilla JS code. The default value is false.\n  config.turbolinks = true # Enable this option if you are using Turbolinks 5+. The default value is false.\n  config.turbo = true # Enable this option if you are using Turbo. The default value is false.\n  config.replace_container = false # Set to false if you want to keep the placeholder div element from render_async. The default value is true.\n  config.nonces = true # Set to true if you want render_async's javascript_tag always to receive nonce: true. The default value is false.\nend\n```\n\nAlso, you can do it like this:\n```rb\n# This will render jQuery code, and skip Vanilla JS code\nRenderAsync.configuration.jquery = true\n```\n\nAside from configuring whether the gem relies on jQuery or VanillaJS, you can\nconfigure other options:\n\n- `turbolinks` option - If you are using Turbolinks 5+, you should enable this option since it supports Turbolinks way of loading data. The default value for this option is false.\n- `turbo` option - If you are using Turbo, you should enable this option since it supports Turbo way of loading data. The default value for this option is false.\n- `replace_container` option - If you want render_async to replace its container with the request response, turn this on. You can turn this on globally for all render_async calls, but if you use this option in a specific render_async call, it will override the global configuration. The default value is true.\n- `nonces` - If you need to pass in `nonce: true` to the `javascript_tag` in your application, it might make sense for you to turn this on globally for all render_async calls. To read more about nonces, check out [Rails' official guide on security](https://edgeguides.rubyonrails.org/security.html). The default value is false.\n\n## :hammer_and_pick: Development\n\nAfter checking out the repo, run `bin/setup` to install dependencies. Then, run\n`rake spec` to run the tests. You can also run `bin/console` for an interactive\nprompt that will allow you to experiment. To run integration tests, use\n`bin/integration-tests`. For more information, check out [CONTRIBUTING](.github/CONTRIBUTING.md) file, please.\n\nGot any questions or comments about development (or anything else)?\nJoin [render_async's Discord channel](https://discord.gg/SPfbeRm)\nand let's make `render_async` even better!\n\n## :pray: Contributing\n\nCheck out [CONTRIBUTING](.github/CONTRIBUTING.md) file, please.\n\nGot any issues or difficulties?\nJoin [render_async's Discord channel](https://discord.gg/SPfbeRm)\nand let's make `render_async` even better!\n\n## :memo: License\n\nThe gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).\n\n## Contributors\n\nThanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)):\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --\u003e\n\u003c!-- prettier-ignore --\u003e\n| [\u003cimg src=\"https://avatars2.githubusercontent.com/u/3028124?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eNikola Đuza\u003c/b\u003e\u003c/sub\u003e](https://nikolalsvk.github.io)\u003cbr /\u003e[💬](#question-nikolalsvk \"Answering Questions\") [💻](https://github.com/renderedtext/render_async/commits?author=nikolalsvk \"Code\") [📖](https://github.com/renderedtext/render_async/commits?author=nikolalsvk \"Documentation\") [👀](#review-nikolalsvk \"Reviewed Pull Requests\") | [\u003cimg src=\"https://avatars0.githubusercontent.com/u/3866868?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eColin\u003c/b\u003e\u003c/sub\u003e](http://www.colinxfleming.com)\u003cbr /\u003e[💻](https://github.com/renderedtext/render_async/commits?author=colinxfleming \"Code\") [📖](https://github.com/renderedtext/render_async/commits?author=colinxfleming \"Documentation\") [💡](#example-colinxfleming \"Examples\") | [\u003cimg src=\"https://avatars2.githubusercontent.com/u/334273?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eKasper Grubbe\u003c/b\u003e\u003c/sub\u003e](http://kaspergrubbe.com)\u003cbr /\u003e[💻](https://github.com/renderedtext/render_async/commits?author=kaspergrubbe \"Code\") | [\u003cimg src=\"https://avatars2.githubusercontent.com/u/163584?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eSai Ram Kunala\u003c/b\u003e\u003c/sub\u003e](https://sairam.xyz/)\u003cbr /\u003e[📖](https://github.com/renderedtext/render_async/commits?author=sairam \"Documentation\") | [\u003cimg src=\"https://avatars2.githubusercontent.com/u/3065882?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eJosh Arnold\u003c/b\u003e\u003c/sub\u003e](https://github.com/nightsurge)\u003cbr /\u003e[💻](https://github.com/renderedtext/render_async/commits?author=nightsurge \"Code\") [📖](https://github.com/renderedtext/render_async/commits?author=nightsurge \"Documentation\") | [\u003cimg src=\"https://avatars3.githubusercontent.com/u/107798?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eElad Shahar\u003c/b\u003e\u003c/sub\u003e](https://eladshahar.com)\u003cbr /\u003e[💻](https://github.com/renderedtext/render_async/commits?author=SaladFork \"Code\") [💡](#example-SaladFork \"Examples\") | [\u003cimg src=\"https://avatars3.githubusercontent.com/u/232392?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eSasha\u003c/b\u003e\u003c/sub\u003e](http://www.revzin.co.il)\u003cbr /\u003e[💻](https://github.com/renderedtext/render_async/commits?author=sasharevzin \"Code\") [📖](https://github.com/renderedtext/render_async/commits?author=sasharevzin \"Documentation\") |\n| :---: | :---: | :---: | :---: | :---: | :---: | :---: |\n| [\u003cimg src=\"https://avatars3.githubusercontent.com/u/50223?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eErnest Surudo\u003c/b\u003e\u003c/sub\u003e](http://elsurudo.com)\u003cbr /\u003e[💻](https://github.com/renderedtext/render_async/commits?author=elsurudo \"Code\") | [\u003cimg src=\"https://avatars1.githubusercontent.com/u/334809?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eKurtis Rainbolt-Greene\u003c/b\u003e\u003c/sub\u003e](https://kurtis.rainbolt-greene.online)\u003cbr /\u003e[💻](https://github.com/renderedtext/render_async/commits?author=krainboltgreene \"Code\") | [\u003cimg src=\"https://avatars2.githubusercontent.com/u/59744?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eRichard Schneeman\u003c/b\u003e\u003c/sub\u003e](https://www.schneems.com)\u003cbr /\u003e[📖](https://github.com/renderedtext/render_async/commits?author=schneems \"Documentation\") | [\u003cimg src=\"https://avatars1.githubusercontent.com/u/75705?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eRichard Venneman\u003c/b\u003e\u003c/sub\u003e](https://www.cityspotters.com)\u003cbr /\u003e[📖](https://github.com/renderedtext/render_async/commits?author=richardvenneman \"Documentation\") | [\u003cimg src=\"https://avatars3.githubusercontent.com/u/381395?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eFilipe W. Lima\u003c/b\u003e\u003c/sub\u003e](https://github.com/filipewl)\u003cbr /\u003e[📖](https://github.com/renderedtext/render_async/commits?author=filipewl \"Documentation\") | [\u003cimg src=\"https://avatars0.githubusercontent.com/u/3135638?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eJesús Eduardo Clemens Chong\u003c/b\u003e\u003c/sub\u003e](https://github.com/eclemens)\u003cbr /\u003e[💻](https://github.com/renderedtext/render_async/commits?author=eclemens \"Code\") | [\u003cimg src=\"https://avatars3.githubusercontent.com/u/1935686?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eRené Klačan\u003c/b\u003e\u003c/sub\u003e](https://github.com/reneklacan)\u003cbr /\u003e[💻](https://github.com/renderedtext/render_async/commits?author=reneklacan \"Code\") [📖](https://github.com/renderedtext/render_async/commits?author=reneklacan \"Documentation\") |\n| [\u003cimg src=\"https://avatars1.githubusercontent.com/u/1313442?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eGil Gomes\u003c/b\u003e\u003c/sub\u003e](http://gilgomes.com.br)\u003cbr /\u003e[📖](https://github.com/renderedtext/render_async/commits?author=gil27 \"Documentation\") | [\u003cimg src=\"https://avatars0.githubusercontent.com/u/6081795?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eKhoa Nguyen\u003c/b\u003e\u003c/sub\u003e](https://github.com/ThanhKhoaIT)\u003cbr /\u003e[💻](https://github.com/renderedtext/render_async/commits?author=ThanhKhoaIT \"Code\") [📖](https://github.com/renderedtext/render_async/commits?author=ThanhKhoaIT \"Documentation\") | [\u003cimg src=\"https://avatars2.githubusercontent.com/u/8645918?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003ePreet Sethi\u003c/b\u003e\u003c/sub\u003e](https://www.linkedin.com/in/preetsethila/)\u003cbr /\u003e[💻](https://github.com/renderedtext/render_async/commits?author=preetsethi \"Code\") | [\u003cimg src=\"https://avatars3.githubusercontent.com/u/11586335?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003efangxing\u003c/b\u003e\u003c/sub\u003e](https://github.com/fffx)\u003cbr /\u003e[💻](https://github.com/renderedtext/render_async/commits?author=fffx \"Code\") | [\u003cimg src=\"https://avatars3.githubusercontent.com/u/1191418?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eEmmanuel Pire\u003c/b\u003e\u003c/sub\u003e](http://blog.lipsumarium.com)\u003cbr /\u003e[💻](https://github.com/renderedtext/render_async/commits?author=lipsumar \"Code\") [📖](https://github.com/renderedtext/render_async/commits?author=lipsumar \"Documentation\") | [\u003cimg src=\"https://avatars1.githubusercontent.com/u/615509?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eMaxim Geerinck\u003c/b\u003e\u003c/sub\u003e](https://github.com/maximgeerinck)\u003cbr /\u003e[💻](https://github.com/renderedtext/render_async/commits?author=maximgeerinck \"Code\") | [\u003cimg src=\"https://avatars1.githubusercontent.com/u/251706?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eDon\u003c/b\u003e\u003c/sub\u003e](https://github.com/vanboom)\u003cbr /\u003e[💻](https://github.com/renderedtext/render_async/commits?author=vanboom \"Code\") |\n| [\u003cimg src=\"https://avatars0.githubusercontent.com/u/998682?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003evillu164\u003c/b\u003e\u003c/sub\u003e](https://github.com/villu164)\u003cbr /\u003e[📖](https://github.com/renderedtext/render_async/commits?author=villu164 \"Documentation\") | [\u003cimg src=\"https://avatars.githubusercontent.com/u/11203679?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eMitchell Buckley\u003c/b\u003e\u003c/sub\u003e](https://github.com/Mbuckley0)\u003cbr /\u003e[💻](https://github.com/renderedtext/render_async/commits?author=Mbuckley0 \"Code\") [📖](https://github.com/renderedtext/render_async/commits?author=Mbuckley0 \"Documentation\") | [\u003cimg src=\"https://avatars.githubusercontent.com/u/15371677?v=4\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eyhirano55\u003c/b\u003e\u003c/sub\u003e](https://github.com/yhirano55)\u003cbr /\u003e[💻](https://github.com/renderedtext/render_async/commits?author=yhirano55 \"Code\") [📖](https://github.com/renderedtext/render_async/commits?author=yhirano55 \"Documentation\") |\n\u003c!-- ALL-CONTRIBUTORS-LIST:END --\u003e\n\nThis project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnikolalsvk%2Frender_async","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnikolalsvk%2Frender_async","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnikolalsvk%2Frender_async/lists"}