Web Development

Easily Create Interactive UIs in Pure Ruby

Easily Create Interactive UIs in Pure Ruby

by Jonas Jabari

In this talk, Jonas Jabari introduces Mate Stack UI, a framework aimed at creating dynamic web interfaces using pure Ruby. The framework addresses the challenges faced by Ruby on Rails developers in managing complex user interfaces, traditionally handled through HTML, CSS, and JavaScript. The presentation highlights the desire to streamline this process, delivering a more cohesive and manageable framework without relying heavily on JavaScript.

Key Points Discussed:
- Introduction to Mate Stack UI: Jabari explains that Mate Stack enables the development of dynamic UIs exclusively in Ruby, positioning it as a solution that simplifies and improves the user interface creation process.
- The Challenge of Traditional Approaches: The speaker contrasts two approaches to UI design in Rails: writing embedded Ruby (ERB) templates or creating standalone JavaScript applications, both of which present their limitations. The former results in poorly organized code, while the latter creates complexity with two separate applications.
- Mate Stack’s Approach: By introducing Mate Stack, developers can define user interface components (pages, components, and app layouts) using Ruby. This allows for a clean syntax that avoids the need to switch between languages, managing everything within Ruby classes.
- Dynamic Behavior with No JavaScript: Jabari demonstrates how Mate Stack handles transitions and dynamic elements through Ruby, allowing for actions like button clicks and form submissions to update the UI without reloading the page. This simplifies the development process while still achieving a reactive interface.
- Key Features Explored: Through live coding, Jabari showcases the framework’s handling of events, form submissions, and validation feedback, all designed to be intuitive and straightforward to implement.
- Customization and Extensibility: Mate Stack is built with the intent to support customization, enabling developers to create their components in addition to utilizing the built-in options. Jabari emphasizes that it is open-source and can be extended using Vue.js for specific requirements.
- Optimizations and Future Developments: The presenter acknowledges that while performance is currently not optimized compared to traditional methods, plans for future improvements are in place, including server-side caching.
- Audience Engagement: The talk concludes with an invitation for audience participation and feedback, encouraging attendees to explore the framework further and contribute to its development.

Main Takeaways:

  • Mate Stack UI offers a way to build dynamic web applications using pure Ruby, reducing the need for JavaScript.
  • The framework is focused on simplifying the development process while keeping the UI maintainable and coherent.
  • Future iterations of the framework will seek to enhance performance and adopt user suggestions for improvements.
00:00:02.610 Are you ready for the next talk? I want to introduce our next speaker.
00:00:09.510 His topic is Mate Stack UI, and I want to give a huge shout-out to him.
00:00:16.500 Thank you! Ok, hi everyone.
00:00:24.439 I want to introduce you to Mate Stack UI. If you don't know what Mate Stack is, I'm going to change that during this talk.
00:00:31.649 The goal is to rapidly create a dynamic web UI in pure Ruby. I pitched it this morning, and I'm going to give a longer version of the pitch right now.
00:00:37.829 First of all, I'm Jonas. I studied mechanical engineering and taught myself software engineering during my studies.
00:00:43.230 I fell in love with software engineering, but if I take a moment, you might wonder why that is.
00:00:51.329 I didn't study computer science, so I have a very high-level view on software engineering.
00:00:56.820 You might have noticed that I'm a co-founder of Base Mate, a software service agency.
00:01:03.120 I'm the creative mastermind, and that's why I wanted to introduce Mate Stack today.
00:01:10.800 Now, I have some questions. Please raise your hands: Who of you loves to write HTML?
00:01:18.030 Ok, who loves to write CSS?
00:01:27.030 And who loves to create a JavaScript mess for some dynamic behavior?
00:01:39.150 Oh yeah, that's quite a few hands! And who has to implement Ruby business logic?
00:01:48.810 Exactly, it's a tough situation.
00:01:54.360 I didn't expect so many hands for HTML and CSS! So, why this talk?
00:02:05.190 I should have looked there; by the way, this is my first talk in front of an audience with this type of microphone.
00:02:11.640 Let's have a look at how a Rails developer faces the challenge of creating a dynamic user interface.
00:02:17.560 We'll examine how much Ruby can be used while facing this challenge.
00:02:29.980 We model the database, use Active Record, and it's beautiful.
00:02:35.530 We love it! The definition and the API are fantastic; many people adore them.
00:02:43.230 We use controllers, such as the application controller, and everything just works.
00:02:49.270 The code looks nice and is highly maintainable.
00:02:54.840 In my opinion, it's also very beautiful.
00:03:02.080 We use gems like Devise to set up authentication; we all know that.
00:03:08.080 You can connect it to your controller, and the architecture is clean and maintainable.
00:03:16.830 It is stunning.
00:03:23.050 Then, personally, I use Pundit for authorization. There are multiple gems for that.
00:03:32.050 We can handle more than just authentication; we also manage authorization beautifully.
00:03:37.680 And we define routes according to what Rails has to offer, which is also beautiful.
00:03:46.750 You can accomplish a lot and perform many magic tasks, saving time and delivering applications quickly.
00:03:55.470 Everything looked good until now, but then the view layer comes into play.
00:04:01.750 That's at least my reaction when I start implementing the view layer.
00:04:12.580 So, you essentially have two options: you can write .erb or humble views.
00:04:18.940 You can manage to avoid writing proper Ruby while adding some JavaScript for dynamic behavior.
00:04:30.400 However, this method often leads to a poorly structured view layer.
00:04:38.520 At least it's part of your Rails application.
00:04:44.139 Alternatively, you can use a modern approach and create a standalone JavaScript application.
00:04:52.060 You can leverage one of the major JavaScript frameworks.
00:04:57.550 In this scenario, Rails is often used just as a JSON API.
00:05:05.349 You handle all the rendering in your standalone JavaScript application.
00:05:12.039 This leads to having a well-structured view layer since they offer good software design.
00:05:20.770 You don't want to say anything negative about that.
00:05:26.800 This approach is well-structured, but it means you have to write a lot of JavaScript.
00:05:33.009 This is where the problem begins because I don't enjoy that.
00:05:38.469 The most important consideration is maintaining two different applications: your Rails back-end and your JavaScript front-end.
00:05:46.029 You have to align these systems and create APIs, which often leads to losing functionality.
00:05:52.569 You may find yourself managing authentication and authorization across both systems.
00:06:00.990 You even have translations living in the back-end, and you need to duplicate them somehow on the front-end.
00:06:07.990 In my opinion, there are many disadvantages to having two different applications, two repositories, and two test suites.
00:06:13.860 We don't like either approach, obviously. If I say 'we,' I mean me, my colleagues, and some people I know.
00:06:21.389 The first approach, the HTML/ERB or Slim option, feels too limited.
00:06:28.650 The second approach, creating a standalone JavaScript application, is deemed too complex.
00:06:35.710 This gap in between is why we created Mate Stack.
00:06:46.670 I would like to show you real working code to give you an idea of how we want to fill that gap.
00:06:53.980 Now, I'm switching to my editor. From now on, I encourage you to ask questions right away.
00:07:03.419 If I'm going too fast, it's because everything looks perfectly natural to me. So let me know if you don't understand anything.
00:07:10.210 Ok, nice. We have a not styled app here.
00:07:16.560 On purpose, I haven't added any styles because we're focusing on functionality right now, not about Bootstrap or Material Design.
00:07:22.020 So, let's have a look at what Mate Stack looks like. I'm going to switch to the editor.
00:07:30.889 Is that ok for everyone? I can make it a bit bigger.
00:07:39.300 Better? Still a bit too small? Ok, I think it's fine.
00:07:44.520 Alright, cool. So, we can see part of the page here.
00:07:50.789 Actually, don’t care too much about what this is on top. As you can see, it's a Ruby class.
00:07:57.210 We should have a look at the response part. Mate Stack has the concepts of a page, a component, and an app.
00:08:03.539 These are the three major building blocks, and we will see what each one entails.
00:08:08.789 At the moment, we're looking at the page class, which has a response function.
00:08:13.889 In this response function, the page orchestrates components.
00:08:20.669 In this case, we describe how the user interface should look.
00:08:26.550 If we switch back, we see this output: 'Hello from page one.' This is, obviously, the first output we orchestrated.
00:08:32.849 This is a heading component, similar to an h2 HTML tag. This is our component call.
00:08:39.240 We have a div; we know what that is, and if we wrap plain text output... hello from page one.
00:08:46.380 The first thing we see here is that we are not writing HTML; we're writing Ruby in a Ruby class.
00:08:53.160 You can imagine we could put a lot of Ruby on top of it. Now we're going to do just that.
00:09:01.660 But that's just the first major component.
00:09:05.910 We describe the user interface in Ruby.
00:09:12.660 The next thing to examine is that there's more on this page.
00:09:18.810 There's obviously some kind of layout, like a title and a navigation bar.
00:09:24.370 So a page may have a layout, and we called it the Mate Stack app.
00:09:31.759 The Mate Stack app can contain multiple pages, but at its core, an app is just a layout for a page.
00:09:38.410 The term 'app' sounds fancier.
00:09:44.710 Again, we have different classes at play here, and now we have the app class.
00:09:50.080 We're applying the same principle that we have a response function orchestrating components.
00:09:57.370 We can have an h1 tag with the text 'My App,' followed by a navigation part with transition components.
00:10:04.210 These are special Mate Stack components you'll see what they do. You might expect what they will do.
00:10:10.950 Again, we declare our user interface with some buttons.
00:10:18.980 Here we have six buttons, each leading to different routes.
00:10:25.680 We also have a main part, a content area for the page, which behaves like a Rails layout.
00:10:32.700 It has a yield like Rails layouts do.
00:10:39.400 What you just saw is the first page with this content filled into the layout.
00:10:46.100 Again, that's just the basics. Mate Stack serves static content, but magic happens now.
00:10:53.500 If I click this button, it may not be easy to see, but there is no page reload.
00:11:00.470 It internally switches out these two pages.
00:11:09.750 We'll quickly have a look at page two.
00:11:15.370 Page two, as we introduced here, uses a prepare statement. This should be done before rendering.
00:11:21.100 So we initialize an array of strings and orchestrate some sub-components.
00:11:28.929 As you can see, they are just HTML tags familiar to you, but implemented in Ruby.
00:11:35.570 We have a list, and we iterate through this array to display the content.
00:11:42.460 The main thing is that the transition between these two pages is done through Mate Stack magic.
00:11:49.640 No JavaScript is involved on our part.
00:11:56.100 This is critical for us as it's a classic requirement for a dynamic user interface.
00:12:02.370 You want to handle page transitions with animations and loading bars. Normally, this would require writing JavaScript.
00:12:10.860 But because it's a classic requirement, we don't want to write JavaScript.
00:12:18.430 We want to define the behavior in a Ruby class where it can just happen automatically.
00:12:25.900 This is one of the main concepts of Mate Stack: dynamic page transitions.
00:12:32.570 I can show you how that looks if you take a look at the network.
00:12:39.450 Just to wait, I will switch to page one.
00:12:47.670 As I switch, I just get the content back from the server for page one.
00:12:54.800 Mate Stack's JavaScript, which is based on Vue.js, takes this content and displays it in the area.
00:13:02.209 If you can imagine, that's the same structure.
00:13:09.639 Ok, questions up to this point?
00:13:16.339 Until now, we have seen two major things: HTML written in a Ruby class and dynamic page transitions.
00:13:23.060 These are based on some magic, and Mate Stack ships them automatically.
00:13:30.519 Any questions? Is everything clear?
00:13:35.950 Cool. There was a question, right?
00:13:42.090 Just a quick question: is this compatible with other Ruby-based frameworks like Sinatra, or is it mostly a Rails gem?
00:13:48.420 Currently, it's built for Rails, but I know that this can be a requirement, and we are looking to port it to other Ruby frameworks.
00:13:56.540 At the moment, I started with Rails because we do client projects there and validate our ideas in our daily business.
00:14:03.880 So I didn't want to build something that doesn't work in reality.
00:14:08.070 That's why we built a Rails engine; you just plug it into your Rails application.
00:14:15.640 Then you get these functionalities out-of-the-box. We use that in our production client systems.
00:14:21.990 Ok, Mate Stack has a lot more to offer. We will see a bit of that right now.
00:14:29.300 Now we're going to dynamically transition to page three without a page reload!
00:14:35.950 And here it is, page three! Let's see what happens next.
00:14:43.390 There’s a button and a date string, so if I click it, you'll see a new string.
00:14:50.380 And some kind of notification will appear. Let's see how this is implemented on my third page.
00:14:58.360 Once again, we orchestrate components in this page. We have our action component.
00:15:07.530 This component gets a configuration, which is defined in a Ruby function.
00:15:14.130 This Ruby function returns a hash informing the action component what to do.
00:15:20.550 We want to perform a post request to this path, which is just a Rails route.
00:15:27.240 If it succeeds, we want to emit this event. If it fails, we want to submit this event.
00:15:34.790 This is the event configuration. The action expects to visualize the action.
00:15:41.550 We could actually put any component here, but we decide to place a button with the text 'Click Me'.
00:15:49.240 So that's why you saw 'Click Me,' which obviously performs post requests.
00:15:55.860 Now, what happens after I clicked it will be the re-rendering of this part of the UI, showing the state string.
00:16:02.899 This occurs because I told this part of the UI to asynchronously re-render if an event is received.
00:16:08.750 We saw that the event is emitted if the action succeeded.
00:16:15.500 So, obviously, the controller behind this succeeded, allowing the event to be emitted.
00:16:22.350 The component visualizes this state string that gets pre-rendered.
00:16:29.260 We do something similar, but with a different approach on this segment of the UI.
00:16:35.670 There’s also a swing component, but now we declare it to show on this event.
00:16:41.610 It will hide after two thousand milliseconds.
00:16:48.950 This is why we could see the notification for two seconds after the action succeeded.
00:16:55.880 This leads to dynamic feedback, which we describe with a few lines of Ruby.
00:17:02.900 No JavaScript is involved in this process.
00:17:09.090 This is also a classic requirement for a dynamic user interface.
00:17:16.290 We want to respond dynamically to back-end reactions.
00:17:23.020 If the action would have failed, we would have seen the notification appearing for two seconds.
00:17:30.360 This is a new concept we just introduced. Any questions up to here?
00:17:36.480 Yes, please wait.
00:17:43.640 I'm just wondering what 'pg' stands for?
00:17:50.180 Oh, sorry. That's a paragraph tag because, in HTML, it's just 'p'.
00:17:57.810 But in Ruby, we couldn't use that directly.
00:18:02.430 So we used 'pg.' Sorry for that! We implement around twenty classic HTML tags, including div, ul, li, table, and spans.
00:18:09.710 PG corresponds to a paragraph tag.
00:18:14.670 Does the event system support more data payload in the event?
00:18:22.900 Yes, it does, but I think I can’t cover it right now.
00:18:30.440 But it is fully supported.
00:18:36.760 I think I have to hurry up; I have ten minutes left, and I'd like to show you much more.
00:18:43.300 Now it’s going to become more interesting. We have a classic requirement: user input.
00:18:50.090 Let's see what happens here. Hello!
00:18:56.170 This was done without a page reload, and part of the UI is re-rendered.
00:19:02.770 I submitted this form using my return key. I'll try to input that again.
00:19:09.150 Oh, it's not working! I see a notification, but then it disappears.
00:19:15.670 You can imagine what that was.
00:19:18.330 The reason is I have a model with validations for title presence and uniqueness.
00:19:25.220 Of course, I tried to create the same instance of the dummy model with the same title.
00:19:31.730 Active Record was unhappy about that, and the validation error messages were dynamically included in the UI.
00:19:38.440 Let's examine how this is implemented because it's another classic requirement.
00:19:45.300 We have again our page prepared, representing a new instance of the dummy model for our form.
00:19:51.700 We have some headings here, and now we focus on a form component.
00:20:00.700 It makes a component component, and it's configured again.
00:20:07.640 This configuration is stored in this method.
00:20:14.160 The form for the dummy model instance specifies what to do.
00:20:20.020 It should perform a post against this path with the input.
00:20:26.830 Similar to the action component, it expects success and failure events.
00:20:33.480 We tell the form that it should ask for the title, mark it as text, and set the placeholder.
00:20:39.820 We make it need a paragraph for spacing, but I don’t want to decide anything here.
00:20:47.050 Finally, for form submission, we want to visualize this action as a button.
00:20:54.240 This is what we see here: an input button.
00:21:00.740 Now, Mate Stack performs the magic with validation from Active Record.
00:21:05.770 Since it wasn’t unique, we see our validation error in the UI.
00:21:12.030 This is just a form input.
00:21:18.810 We have a list that displays each dummy model title for this iteration.
00:21:24.280 This is paired with a sink that reacts on the form's success event.
00:21:31.030 This is why this part is re-rendered after successfully submitting the form with a new dummy model included.
00:21:37.480 Just one more thing here, and then I’ll take some questions.
00:21:44.220 On the right side, we see page five, and on the left side, there's still page four.
00:21:50.640 Let's take a look at this part of the UI.
00:21:57.760 There are two different browser sessions, and there are some broadcasters involved.
00:22:05.740 So, Action Cable is involved. The great part is that it's very easy to implement a reactive user interface.
00:22:12.590 Let's check out page five. We see some headings and another component.
00:22:19.220 Again, this is a swing component that just displays a list of dummy models.
00:22:25.850 We instruct the sync component to rerender upon receiving an event.
00:22:34.060 It's a sync rerender based on an event, and no JavaScript is involved.
00:22:41.410 The only thing we need to manage is creating a form.
00:22:47.520 We create a form action with our parameters. Everything is classic Rails.
00:22:55.120 If there's an error, we respond with an error code. If not, we broadcast that the model was created.
00:23:00.440 This is the event that sync was waiting for to render.
00:23:08.059 At the moment, we can broadcast this to a specific channel.
00:23:15.860 That’s it; it's achievable with no JavaScript involved.
00:23:22.500 We are now looking at a WebSockets-based user interface.
00:23:28.650 Now, that's hopefully nice!
00:23:35.170 Wait a second; I need to address this.
00:23:40.640 We just saw Mate Stack utilizing components in action.
00:23:47.160 This library is well documented and tested to show you how to utilize its configuration.
00:23:55.210 If this isn't enough, you might want to create your own components.
00:24:02.690 I'm not going to go into detail about that now, but you can create your own custom components.
00:24:11.760 Mate Stack is based on UJS, so it abstracts UJS and Rails communication.
00:24:19.800 As a result, Mate Stack comes with a lot of UJS under the hood.
00:24:26.200 If you want to extend Mate Stack, you should write a Vue.js component.
00:24:32.100 Place it next to the core components.
00:24:38.180 Let’s quickly look at the sixth page, showing core components in action.
00:24:46.070 We have a heading core component and a custom demo component.
00:24:53.290 Remember: 'custom' is the namespace you need to create your own components.
00:25:00.270 The custom demo component uses Mate Stack's Ruby templating.
00:25:08.230 You simply add Ruby and Vue.js directives.
00:25:15.080 Here’s how your custom component will look.
00:25:22.220 It's still a classic UJS component.
00:25:28.930 If you click this button, it triggers an API call.
00:25:36.640 It is just classic Vue.js—nothing too fancy.
00:25:42.480 It just iterates through the received data.
00:25:48.860 This is how you could extend Mate Stack. There are really no limits!
00:25:58.220 However, the intention was that around 80 to 90 percent of classic web-driven data-driven UIs.
00:26:05.520 They can be orchestrated using these core components.
00:26:12.740 For highly specific behaviors, you simply create your own components.
00:26:18.760 Place them next to all the core components without making a mess.
00:26:29.480 In our opinion, it’s well architecture overall.
00:26:35.920 Now, you might ask how this connects through routes to controllers.
00:26:43.350 You just use classic routes—there's nothing different here.
00:26:49.790 First page, second page, whatever. You construct your controllers as you wish.
00:26:55.679 You have your actions, and you put this helper function in your class.
00:27:03.020 This tells the Rails action to use the Mate Stack class to render the result.
00:27:09.190 That’s how everything is interconnected.
00:27:15.370 We don’t touch anything else from Rails because we love Rails.
00:27:20.680 We wanted the option to add a new view layer on top of everything else Rails has to offer.
00:27:27.930 You can do this progressively, action by action, deciding whether you want to respond with a Mate Stack page.
00:27:36.320 That's it for now! Any questions are welcome.
00:27:43.480 Actually, it's 3 AM, so maybe we can have just one or two questions.
00:27:49.570 Do you have any benchmarks for how fast it renders pages in comparison with ERB or Slim?
00:27:55.260 As of now, it’s slower. We don't have benchmarks yet.
00:28:02.490 So far, we primarily focused on creating a working concept and plan to optimize it in the future.
00:28:09.340 We'll look into server-side caching and performance optimizations.
00:28:15.590 In many applications, client budget is the crucial factor rather than performance.
00:28:21.790 But we want to optimize performance as well. Thank you!
00:28:30.060 Which parts of Trailblazer are you using?
00:28:38.920 Unfortunately, you don’t directly touch that.
00:28:45.780 Trailblazer cells are very effective but sometimes too complicated.
00:28:54.820 We want to offer a much easier approach.
00:29:02.180 Finally, just a quick survey: Who here is interested in using this approach?
00:29:10.480 Wow, thank you very much! This is encouraging!
00:29:16.009 If you like what you saw, please visit GitHub and give us a star.
00:29:23.640 Look for Base Mate or Mate Stack; it's open source, so try it out.
00:29:31.149 Feel free to create issues; it's not perfect yet version 0.6.