Action Component API
The action component allows us to trigger async HTTP requests without Javascript!

Parameters

The core action component accepts the following parameters:

Method - required

This specifies which kind of HTTP method should get triggered. It accepts a symbol like so:
1
method: :post
Copied!

Path - required

This parameter accepts a typical Rails path:
1
path: action_test_path
Copied!

Data

Here, we can pass data with our request, e.g. in the form of a hash:
1
data: {
2
foo: 'bar'
3
}
Copied!

Confirm

When specified, a browser-native confirm dialog is shown before the action is actually performed. The action only is performed after the user confirms. The action is not performed if the user declines to confirm dialog.
1
confirm: {
2
text: "Do you really want to delete this item?"
3
}
Copied!
If no text is given, the default text "Are you sure?" will be used.
1
confirm: true
Copied!

Emit

This event gets emitted right after triggering the action. In contrast to the sucsess or failure events, it will be emitted regardless of the server response.
1
emit: "action_submitted"
Copied!

Delay

You can use this attribute if you want to delay the actual action submit request. It will not delay the event specified with the emit attribute.
1
delay: 1000 # means 1000 ms
Copied!

Success

The success part of the action component gets triggered once the action we wanted to perform returns a success code, usually the 200 HTTP status code.
To trigger further behavior, we can configure the success part of an action to emit a message like so:
1
success: {
2
emit: 'my_action_success'
3
}
Copied!

Perform transition

We can also perform a transition that only gets triggered on success and also accepts further params:
1
success: {
2
emit: 'my_action_success',
3
transition: {
4
path: action_test_page2_path(id: 42)
5
}
6
}
Copied!
When the server redirects to a url, for example after creating a new record, the transition needs to be configured to follow this redirect of the server response.
1
success: {
2
emit: 'my_action_success',
3
transition: {
4
follow_response: true
5
}
6
}
Copied!
A controller action that respond with the url the page should transition to, could look like this:
1
class SomeController < ApplicationController
2
3
def some_action
4
# some logic
5
render json: {
6
transition_to: some_path(id: 42)
7
}, status: :ok
8
end
9
10
end
Copied!

Perform redirect

We can also perform a redirect (full page load) that only gets triggered on success and also accepts further params:
Please be aware, that emiting a event doen't have an effect when performing a redirect instead of a transition, as the whole page (including the surrounding app) gets reloaded!
1
success: {
2
emit: 'my_action_success', # doesn't have an effect when using redirect
3
redirect: {
4
path: action_test_page2_path(id: 42)
5
}
6
}
Copied!
When the server redirects to a url, for example after creating a new record, the redirect needs to be configured to follow this redirect of the server response.
1
success: {
2
emit: 'my_action_success', # doesn't have an effect when using redirect
3
redirect: {
4
follow_response: true
5
}
6
}
Copied!
A controller action that respond with the url the page should transition to, could look like this:
1
class SomeController < ApplicationController
2
3
def some_action
4
# some logic
5
render json: {
6
transition_to: some_path(id: 42)
7
}, status: :ok
8
end
9
10
end
Copied!
Same applies for the failure configuration.

Failure

As counterpart to the success part of the action component, there is also the possibility to define the failure behavior. This is what gets triggered after the response to our action returns a failure code, usually in the range of 400 or 500 HTTP status codes.
To trigger further behavior, we can configure the failure part of an action to emit a message like so:
1
failure: {
2
emit: 'my_action_failure'
3
}
Copied!
We can also perform a transition that only gets triggered on failure:
1
failure: {
2
emit: 'my_action_failure',
3
transition: {
4
path: root_path
5
}
6
}
Copied!

ID

This parameter accepts a string of ids that the action component should have:
1
id: 'my-action-id'
Copied!
which renders as an HTML id attribute, like so:
1
<a id="my-action-id">...</a>
Copied!

Class

This parameter accepts a string of classes that the action component should have:
1
class: 'my-action-class'
Copied!
which renders as an HTML class attribute, like so:
1
<a class="my-action-class">...</a>
Copied!

Examples

See some common use cases for the action core component below:

Async request with payload

First, make sure our routes accept requests the way we want to use them. Modify them in config/routes.rb
1
post '/action_test', to: 'action_test#test', as: 'action_test'
Copied!
After that, you can specify an action on our example page. Notice how we wrap a button to have something visible to click and trigger the action!
1
class ExamplePage < Matestack::Ui::Page
2
3
def response
4
# our action component wraps a simple button
5
action action_config do
6
button 'Click me!'
7
end
8
end
9
10
# this is where our action is defined
11
def action_config
12
return {
13
method: :post,
14
path: action_test_path,
15
data: {
16
foo: 'bar'
17
}
18
}
19
end
20
21
end
Copied!
In this case, the ActionTestController receives :foo => 'bar' in the params.

Async request with URL param

Instead of sending raw data, we can also explicitly pass params to a route. Like in the example above, we open up the route we intend to use in config/routes.rb:
1
post '/action_test/:id', to: 'action_test#test', as: 'action_test_with_url_param'
Copied!
And on the example page, we specify our action component's behavior:
1
class ExamplePage < Matestack::Ui::Page
2
3
def response
4
# our action component again wraps a button
5
action action_config do
6
button 'Click me!'
7
end
8
end
9
10
def action_config
11
return {
12
method: :post,
13
path: action_test_with_url_param_path(id: 42)
14
}
15
end
16
17
end
Copied!
This example simply sends the param :id => '42' to the route we have defined!

Success/Failure Behavior

Now, we examine different cases on how to handle success/failure scenarios.
Again, we look at our routes beforehand. This time, we define two different endpoints in config/routes.rb:
1
post '/success_action_test', to: 'action_test#success_test', as: 'success_action_test'
2
post '/failure_action_test', to: 'action_test#failure_test', as: 'failure_action_test'
Copied!
Let's also take a look at the app/controllers/action_test_controller.rb to see what the endpoints do:
1
class ActionTestController < TestController
2
3
def success_test
4
render json: { message: 'server says: good job!' }, status: 200
5
end
6
7
def failure_test
8
render json: { message: 'server says: something went wrong!' }, status: 400
9
end
10
11
end
Copied!

Async request with success event emit used for rerendering

Below, we define an action component and an async component. The async component is documented here, for now it is just important that it waits for our action_config success message and will get re-rendered.
1
class ExamplePage < Matestack::Ui::Page
2
3
def response
4
# this is our action component
5
action action_config do
6
button 'Click me!'
7
end
8
# here, we have an async component gets re-rendered on action success
9
async rerender_on: 'my_action_success', id: "my-async-component" do
10
div id: 'my-div' do
11
plain "#{DateTime.now.strftime('%Q')}"
12
end
13
end
14
end
15
16
def action_config
17
return {
18
method: :post,
19
path: success_action_test_path,
20
success: {
21
emit: 'my_action_success'
22
}
23
}
24
end
25
26
end
Copied!
Now, if we click the button and everything goes well (which should be the case in this very simple example), we can see the timestamp gets updated - nice!

Async request with success event emit used for notification

In this example, we will show a message that gets triggered once the controller returns a status code of 200:
1
class ExamplePage < Matestack::Ui::Page
2
3
def response
4
# same configuration as before
5
action action_config do
6
button 'Click me!'
7
end
8
# different async behavior
9
toggle show_on: 'my_action_success', hide_after: 300 do
10
plain '{{ event.data.message }}'
11
end
12
end
13
14
def action_config
15
return {
16
method: :post,
17
path: success_action_test_path,
18
success: {
19
emit: 'my_action_success'
20
}
21
}
22
end
23
24
end
Copied!
This time, after clicking our action component we should see the good job! message that was initially hidden and disappears again after 300ms.

Async request with failure event emit used for notification

In the examples before, we always assumed (and made sure) that things went well. Now, it's the first time to use the failure_action_test_path to see how we can notify the user if things go wrong!
1
class ExamplePage < Matestack::Ui::Page
2
3
def response
4
# our good old action including a button
5
action action_config do
6
button 'Click me!'
7
end
8
# success message, initially hidden and removed after 300ms
9
toggle show_on: 'my_action_success', hide_after: 300 do
10
plain '{{ event.data.message }}'
11
end
12
# failure message, initially hidden and removed after 300ms
13
toggle show_on: 'my_action_failure', hide_after: 300 do
14
plain '{{ event.data.message }}'
15
end
16
end
17
18
def action_config
19
return {
20
method: :post,
21
# notice that we post to the failure path on purpose to receive a status code of 500
22
path: failure_action_test_path,
23
success: {
24
emit: 'my_action_success'
25
},
26
failure: {
27
emit: 'my_action_failure'
28
}
29
}
30
end
31
32
end
Copied!
Now, clicking the button shows the failure message - just as we expected it to!

Async request with success event emit used for transition

Unlike before, we will use the action component to trigger a page transition!
Again, we start by defining our routes in config/routes.rb:
1
scope :action_test do
2
get 'page1', to: 'example_app_pages#page1', as: 'action_test_page1'
3
get 'page2/:id', to: 'example_app_pages#page2', as: 'action_test_page2'
4
end
Copied!
Our example app layout, already including placeholders for success/failure notifications:
1
class Apps::ExampleApp < Matestack::Ui::App
2
3
def response
4
heading size: 1, text: 'My Example App Layout'
5
main do
6
yield
7
end
8
toggle show_on: 'my_action_success', hide_after: 300 do
9
plain '{{ event.data.message }}'
10
end
11
toggle show_on: 'my_action_failure', hide_after: 300 do
12
plain '{{ event.data.message }}'
13
end
14
end
15
16
end
Copied!
To make a transition from one page to the other work, we need to make both of them available in our controller:
1
class ExampleAppPagesController < ExampleController
2
include Matestack::Ui::Core::Helper
3
4
matestack_app ExampleApp
5
6
def page1
7
render ExampleApp::Pages::ExamplePage
8
end
9
10
def page2
11
render ExampleApp::Pages::SecondExamplePage
12
end
13
14
end
Copied!
The first page, including an action component that performs a page transition to page 2 on success!
1
class ExampleApp::Pages::ExamplePage < Matestack::Ui::Page
2
3
def response
4
h2 'This is Page 1'
5
action action_config do
6
button 'Click me!'
7
end
8
end
9
10
def action_config
11
return {
12
method: :post,
13
path: success_action_test_path,
14
success: {
15
emit: 'my_action_success',
16
transition: {
17
path: action_test_page2_path(id: 42),
18
}
19
}
20
}
21
end
22
23
end
Copied!
The second page, including an action that shows us the failure message we defined in the controller and then transfers us back to page 1.
1
class ExampleApp::Pages::SecondExamplePage < Matestack::Ui::Page
2
3
def response
4
h2 'This is Page 2'
5
action action_config do
6
button 'Click me!'
7
end
8
end
9
10
def action_config
11
return {
12
method: :post,
13
path: failure_action_test_path,
14
failure: {
15
emit: 'my_action_failure',
16
transition: {
17
path: action_test_page1_path
18
}
19
}
20
}
21
end
22
23
end
Copied!
Now, we can visit localhost:3000/action_test/page1 and see our first page, shown by the This is Page 1 text.
There, we can click on our button (Click me!) and get transfered to the second page. There, we see the This is Page 2 text and, for 300ms, our server says: good job! success message. Neat!
If we click the button (Click me!) on the second page, we get the failure message (server says: something went wrong!) and get sent back to page 2, just as we wanted to.
Last modified 7mo ago