Reusable UI components in Ruby on Rails applications
In this article, I would like to talk about an alternative way to organize a frontend for applications on Ruby on Rails. Mostly I work on the backend, but from time to time there are tasks on the front-end and what is often seen there does not inspire any optimism for further work.
applicationfiles, then the contents of these files may not even be “footcloths”, but entire “sheets” of code. Presentations are not easy either, especially
partialswhen they are used to create separate UI components: modal windows, menus, cellars, etc. Sometimes you need to get a little fancy in order to use such a UI component in different representations with different parameters and / or logic.
partials) lie in different directories and each technology has its own file structure. With this approach, the front-end in medium and large applications is hard to maintain, all of these technologies produce a very explosive mixture that can simply explode at any inopportune moment.
Ideally, I wanted the frontend to consist of separate UI components and have an understandable file structure. To solve such problems, the BEM methodology has long existed , therefore it was it that was taken as the basis when creating the Bemer gem .
Bemer allows you to:
- create reusable UI components
- use BEMHTML templates for UI components
- develop applications according to BEM methodology
More information can be found here .
Example file structure when using Sprockets .
Example file structure when using Webpacker .
With Bemer, you can create various kinds of UI components . This example will look at a way in which BEMHTML templates can be used. The basis will be the Modal component from Bootstrap , with the following HTML structure:
In the beginning, you need to create a structure (tree) of the component using a helper
define_component(only for this kind of UI component you can use BEMHTML templates). A possible variant of the structure (tree) of the Modal component:
/ Содержимое файла app/bemer_components/modal/index.html.slim = define_component bem_cascade: false, tag: :div do |component| = component.block :modal, cls: 'modal fade', role: :dialog, tabindex: -1 do |modal| = modal.elem :dialog, role: :document, cls: 'modal-dialog' = modal.elem :content, cls: 'modal-content' = modal.elem :header, cls: 'modal-header' = component.block :close, type: :button, tag: :button, cls: 'close', 'data-dismiss': :modal span aria-hidden='true' × = modal.elem :title, tag: :h4, cls: 'modal-title' = modal.elem :body, cls: 'modal-body' = modal.elem :footer, cls: 'modal-footer'
The structure (tree) of the component consists of blocks and elements (nodes), they act as labels, using which you can change the component using BEMHTML templates, as well as get css classes from the BEM methodology. In this case, the generation of data from the BEM methodology is not needed, so it can be disabled using the parameter
Now, in any view, you can call the Modal component and apply the necessary BEMHTML templates to it:
/ Кнопка для показа модального окна button.btn.btn-primary.btn-lg data-target="#my-modal" data-toggle="modal" type="button" | Launch demo modal / Вызов компонента Modal и применение BEMHTML шаблонов = render_component :modal do |template| = template.block :modal do |modal| = modal.add_attrs id: 'my-modal' = modal.specify(elem: :dialog).add_cls 'modal-lg' = modal.specify(elem: :title).content 'Modal title' = modal.specify(elem: :body).content p Modal body = modal.specify(elem: :footer).content button.btn.btn-default data-dismiss="modal" type="button" Close button.btn.btn-primary type="button" Save changes / Эквивалентный результат = render_component :modal do |template| = template.block(:modal).add_attrs id: 'my-modal' = template.elem(:dialog).add_cls 'modal-lg' = template.elem(:title).content 'Modal title' = template.elem(:body).content p Modal body = template.elem(:footer).content button.btn.btn-default data-dismiss="modal" type="button" Close button.btn.btn-primary type="button" Save changes
Maybe Bemer can help someone:
- clean up front-end in old projects (
Rails >= 3.2.22)
- reorganize the frontend as a UI component
- create separate collections of UI components (like bemer-bootstrap ) and use them in different projects
- make front-end applications more convenient for work
- it is more convenient to develop according to the BEM methodology
In conclusion, I want to say thanks to the entire BEM team for quick feedback, and in particular tadatuta and miripiruni for detailed answers to questions on the BEM methodology and the bem-xjst template engine .