Concepts & Rails Integration
Last updated
Last updated
In order to understand how to use Matestack, we should cover some basic concepts first, talking about:
How is Ruby converted to HTML?
How can reactivity be implemented in pure Ruby without something like Opal?
Matestack’s rendering mechanism takes care of converting Ruby into HTML using the core component library. div
, span
and plain
are actually Ruby method calls, referencing core component classes Matestack::Ui::Core::Div
, Matestack::Ui::Core::Span
and Matestack::Ui::Core::Plain
.
As you can see, these basic core components are mapped to simple HTML tags. matestack-ui-core
ships all kinds of these basic "HTML tag" components enabling you to build a well known DOM structure while writing and utilizing pure Ruby!
As you can see, you can add CSS classes and ids as well as custom tag attributes. This way matestack-ui-core
can be combined with various CSS frameworks or your custom styles. It’s already fun to write pure Ruby instead of HTML or any other templating engine syntax but this approach is really paying of, when you start using Ruby's language features in order to split your UI implementation into various small chunks, organized through included modules, class inheritance or simply multiple Ruby methods within one class!
You can create your own component library containing reusable components serving your specific needs in pure Ruby! Learn more
matestack-ui-core
can be used without any JavaScript involved! The described Vue.js Integration is optional. You can combine the described HTML Rendering with multiple other reactivity systems if you want!
If we use a reactive component, in this example the form
component and pass in some params like “for”, “path” and “method” as a Ruby hash, Matestack’s rendering mechanism detects that the core component form
is a special, so called VueJsComponent
.
These components consist of two files: The Ruby file with a response method and proper Vue.js JavaScript counterpart file. matestack-ui-core
wraps the response of these components in a special component
HTML tag. Within this tag, the is
attribute is referencing the Vue.js JavaScript component and the component-config
attribute contains the parameters we passed into the form. When shipped to the browser, Vue.js will scan the DOM and discover these special HTML component tags. When an appropriate Vue.js JavaScript component is found (in this case the Vue.js component called matestack-ui-core-form
), this Vue.js component gets the specific component-config injected and will be mounted.
****
The core component library contains a growing set of these Vue.js driven components. They enable you to implement a reactive web UI just writing a few lines of Ruby. You’re actually just configuring how prebuilt components should behave in your specific scenario. Behind the scenes it’s just pure Vue.js and no dark magic.
It’s super simple to create your own Vue.js driven components if your custom requirements can not be met by core components! Learn more
Talking about Vue.js driven components brings up one important element of the reactivity system: Events!
Let’s think of the following example: We’re using the reactive form
component to submit some data and the reactive async
component in order to rerender a specific part of the UI. The async
component is also a core VueJs component and will perform a background HTTP request fetching a new version of it’s content at the server. We don’t want to cover the async
in too much detail, it’s just an example how events are used!
After the generated HTML was shipped to the browser and Vue.js mounted all components, the two components are up and running in the web browser. Additionally a Vue.js event hub was mounted. All other components can now emit and receive client side events through that event hub. In our example, we’re configuring the form
component to emit the event submitted
when the form was successfully submitted. Furthermore we configured the async
component to rerender its content when this event is received! This pattern is used for various reactivity features of matestack-ui-core
Your own Vue.js driven components can also be connected to the event hub and therefore interact with all other components! Learn more
Now that we know how Matestack is working under the hood, we should discuss how we can build our UIs with these concepts! Before we review some code, let's start with the basic UI building blocks.
Depending on your desired Rails integration mode (see below), you might only need a subset of the now presented building blocks
Matestack’s basic UI building blocks are called apps, pages and components.
An app can be compared with a Rails layout, a page can be compared with a Rails view and a component can be best compared with a Rails partial.
Apps, pages and components are Ruby classes, implementing a response
method which will then define specific parts of the UI using pure Ruby methods. We will see in a bit how this looks like.
matestack-ui-core
ships all kinds of "HTML-tag" components (like div, span, ul, li ...), helping you to create a well know HTML structure in pure Ruby. These components can be used on apps, pages and other components in order to implement an UI. An automatically included core component registry maps Ruby method calls like div
to the associated Ruby class Matestack::Ui::Core::Div
Bundled with matestack-ui-core
, additionally various Vue.js driven core components enable you to implement reactive web UIs in pure Ruby.
These components can also be used on apps, pages and other components in order to implement an UI.
Reactive Core ComponentsCustom components may use other core/custom (reactive) components in order to define a specific UI. They can be used on apps, pages and other components if correctly registered in a custom component registry. Additionally they can be used on Rails views (see below)
On the above shown example, a reusable card component was created, which can used across the whole application.
Component OverviewIf you need to implement a very specific reactive feature, you can imlement custom Vue.js components like shown below:
As said, a Matestack page can be compared to a Rails view and might be yielded within a layout provided by an associated Matestack app (see below). The page itself uses components (core/custom) in order to define its specific part of the UI.
In this basic example the page is using the core components div
, span
and plain
in order to create the desired UI. Learn more about Pages:
An app uses components in order to define the layout of your application. It might implement a header and a footer for example. Just like a Rails layout would yield a Rails view, an app yields a page. The app uses components (core/custom) in order to define the layout.
In this basic example the app is using the core components heading
and main
and the methodyield_page
in order to yield a page on a specific position. Learn more about Apps:
There are several ways to use the presented building blocks in your Rails app. matestack-ui-core
is designed to be progressively integrated into existing Rails apps and views. Leveraging the full power and beauty is best done when going full Matestack though!
Matestack components on Rails views
→ Only components are used here and there
Full Matestack
→ Apps, pages and components used together as a Rails view layer substitute
If you already have plenty of Rails views (ERB, Haml or Slim) and want to start creating small UI components in pure Ruby, you are able to use properly registered custom components on these existing views. Within these custom components, you can use all kinds of (core/custom/reactive) components. Only the transition
component will not work without a Matestack app in place
The matestack_component
helper is then used on your Rails view, in this case an ERB view:
This approach is suitable for existing apps and a good idea to migrate to Matestack step by step. If you start with a blank Rails app, we recommend to go full Matestack right away**!**
Going full Matestack means, using pages, components and apps as a (scoped) complete substitute for the Rails view layer. We're not using Rails views anymore but Matestack pages instead. This behavior is mainly managed within Rails controllers.
It's totally valid to serve multiple scopes within one Rails app. Think of a web shop Rails app, consisting of a client-facing storefront UI and a backoffice admin UI. You're free to use full Matestack on one scope and a completely different view layer on the other.
In the following example we see a Ruby class called SomeApp
which is inheriting from Matestack::Ui::App
and a Ruby class called SomePage
namespaced in SomeApp::Pages
inheriting from Matestack::Ui::Page
.
Using the concepts described above, these two classes will be processed and converted into HTML, ready to be shipped to the browser.
Let’s review the classic Rails request/response cycle:
A request is coming in and Rails routing is calling the specified Rails controller action. Nothing new here. Within the Rails action we’re now telling the controller not to render a Rails view wrapped in a Rails layout but instead render a Matestack page wrapped in a Matestack app. All other controller based business logic stays untouched. This is why gems like devise or pundit for example can be used in harmony with matestack-ui-core
Thinking of the describe example of a Webshop backoffice admin UI, the implementation with dynamic page transitions may look like this:
In a file structure like:
Learn more about apps, pages and transitions, in order to create SPA-like apps:
SPA Overview