Railbus
Do you want to use autogenerated set of Rails application routes in your JavaScript files?
Do you want to make requests to your routes from JS with human-readable names
like create_news
, update_message
?
Here comes Railbus to you.
Installation
Add this line to your application's Gemfile:
gem 'railbus'
And then execute:
$ bundle install
You may call this to generate example file and install JavaScript dependencies:
$ rails g railbus:install
Or do it manually:
- Run
yarn add @crosspath/yambus
. See its README for usage info. - Recommended step: add adapter for Axios or
fetch
function. Default: add adapter for Axios asyarn add @crosspath/yambus-axios
. - Create
*.js.erb
file inapp/javascript
(e.g.lib/routes.js.erb
) to use it with Webpack:
/* rails-erb-loader-dependencies ../config/routes */
<%= Railbus.generate %>
And the last step, require this file in your .js
files where you want to use
application routes.
import Routes from 'lib/routes'
Usage
In short:
- See output of
rails routes
, it includes route names. You may use these names in JS as functions for requests. - Append
_path
to a route name to get its URL.
Route names in JS depend on route names in Rails:
Action name | HTTP method | Request function | Path function |
---|---|---|---|
index | GET | {plural_name} | {plural_name}_path |
show | GET | {singular_name} | {singular_name}_path |
new | GET | new_{singular_name} | new_{singular_name}_path |
edit | GET | edit_{singular_name} | edit_{singular_name}_path |
create | POST | create_{singular_name} | create_{singular_name}_path |
update | PUT/PATCH | update_{singular_name} | update_{singular_name}_path |
destroy | DELETE | delete_{singular_name} | delete_{singular_name}_path |
Configuration
By default Railbus generates functions for all routes defined
in Rails.application
, and these functions use library axios
.
You may change it:
<%=
Railbus.generate(
# Here `YourApp::Engine` inherits `Rails::Engine`.
# Default: `Rails.application`.
app: YourApp::Engine,
# 'axios', 'fetch' or the name of function defined or imported in this file.
# Appropriate NPM package for adapter should be installed.
# Default: 'axios'.
client: 'request_api',
# Include only these route paths that start with '/api'.
# Empty array: include all routes (default).
include: [%r{^/api}],
# Exclude all route paths matching regexpes.
# Empty array: do not exclude any routes (default).
exclude: [/edit|new/],
# 'null' or the name of function defined or imported in this file.
#
# This function will be called before doing requests. It accepts
# `url`, `options`, `route`, `params` and should return `options`.
#
# You may use it to add options before performing request or for logging
# requests.
#
# Default: 'null' (no function).
set_options: 'null'
)
%>
import axios from 'axios'
// For example, pass all requests to subdomain `api`.
const axios_api = axios.create({
baseURL: `${document.location.protocol}//api.${document.location.host}/`
})
function request_api(route, params, set_options) {
let options = {
url: params.path,
method: route.verb,
params: params.url_options,
data: params.data
}
if (typeof set_options === 'function')
options = set_options(params.path, options, route, params)
return axios_api.request(options)
}
Examples
Let's take these routes as an example:
resources :news do
resources :images, only: %w[index show create update destroy]
end
resources :messages, only: %w[new create]
namespace :my do
resources :favourites, only: %w[index show create update destroy]
end
Assume you have generated object with routes in JS file lib/routes
.
You may do this in JS to call requests:
import Routes from 'lib/routes'
// Request all favourites and print to console. Note: using namespace `my`.
// It will call `My::FavouritesController#index`.
// Path: '/my/favourites'.
Routes.my_favourites().then(resp => console.log(resp.data))
// Request all news and print to console.
// String `index` appended to distinguish `index` and `show` actions.
// It will call `NewsController#index`.
// Path: '/news'.
Routes.news_index().then(resp => console.log(resp.data))
// Request all news filtered by date, and print to console.
// `NewsController#index` with param `date` in query string (GET).
// Path: '/news' with query string '?date=2020-12-31'.
Routes.news_index({date: '2020-12-31'}).then(resp => console.log(resp.data))
// Request one news and print to console.
// `NewsController#show` with param `id` = 327 (GET).
// Path: '/news/327'.
Routes.news(327).then(resp => console.log(resp.data))
// Or
Routes.news({id: 327}).then(resp => console.log(resp.data))
// Specify format (for example, '.json').
// `NewsController#show` with param `id` = 327 (GET) and `format` = 'json'.
// Path: '/news/327.json'.
Routes.news(327, {format: 'json'}).then(resp => console.log(resp.data))
// Or
Routes.news({id: 327, format: 'json'}).then(resp => console.log(resp.data))
// Create news with given title.
// `NewsController#create` with param `title` (POST).
Routes.create_news({title: 'Bears showed up in Tomsk'}).then(resp => {
console.log(resp.data)
})
// Create message with given title. Note: `message`, singular form.
// `MessagesController#create` with params `body`, `to` (POST).
Routes.create_message({body: 'Fantastic!', to: 23}).then(resp => {
console.log(resp.data)
})
// Create message with given title. Note: using namespace `my`.
// `My::FavouritesController#create` with param `url` (POST).
Routes.create_my_favourite({url: 'https://best.site'}).then(resp => {
console.log(resp.data)
})
// Attach an image to the news.
// `ImageController#create` with params `news_id` = 41 (GET),
// `my_attachment` (POST).
Routes.create_news_image(41, {my_attachment: file})
// Get URL for `create` action.
Routes.create_my_favourite_path() // => 'my/favourites'
Development
After checking out the repo, run bin/setup
to install dependencies.
Then, run rake spec
to run the tests. You can also run bin/console
for
an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
.
TODO:
✅ Support fetch — done!
🔲 Tests
Contributing
Bug reports and pull requests are welcome on GitHub at github.com/crosspath/railbus.
Please do not change version number in pull requests.
Alternative solutions
- rswag + swagger-js + your integration specs (tests)
- railsware/js-routes
- mtrpcic/js-routes
- less-js-routes
- js_named_routes
License
The gem is available as open source under the terms of the MIT License.