Project

railbus

0.0
No release in over 3 years
Low commit activity in last 3 years
Generate JS functions for XHR requests to Rails routes
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

>= 0

Runtime

 Project Readme

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:

  1. Run yarn add @crosspath/yambus. See its README for usage info.
  2. Recommended step: add adapter for Axios or fetch function. Default: add adapter for Axios as yarn add @crosspath/yambus-axios.
  3. Create *.js.erb file in app/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:

  1. See output of rails routes, it includes route names. You may use these names in JS as functions for requests.
  2. 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

  1. rswag + swagger-js + your integration specs (tests)
  2. railsware/js-routes
  3. mtrpcic/js-routes
  4. less-js-routes
  5. js_named_routes

License

The gem is available as open source under the terms of the MIT License.