N
N
ned4ded2019-03-28 18:17:26
Ruby on Rails
ned4ded, 2019-03-28 18:17:26

Where to store static variables and constants for view in RoR?

Good afternoon everyone. I mainly work on the front-end (now more vue, but I'm also familiar with angular), I work with rails according to circumstances (the backend of many projects I work on is written on rails). I had a bit of a snag understanding some of the basic concepts that this framework is built on. And the question is more about the representation of data, i.e. more related to views and related logic.
Let's assume that the application has a menu that presents a set of links: events, archive, blog, account, language, entry_btn. Several buttons have conditional dependencies, for example: the language selection button depends on the currently selected language, the content of the entry_btn button and the presence of the account button depends on whether the user is logged in or not.
the simplest, most obvious and well working solution:

/ slim-lang
ul.navbar__menu
  li = link_to 'Events', root_path, class: 'navbar__item'
  / ... other links

  li
    - if I18n.locale == :ru
      link_to 'Eng', locale_path(:en), 'navbar__item'
    - else
      link_to 'Ru', locale_path(:ru), 'navbar__item'

  - if signed_in?
    li = link_to 'Аккаунт', edit_user_registration_path, class: 'navbar__item'
    li = link_to 'Выход', destroy_user_session_path, class: 'navbar__item', method: :delete
  - else 
    li = link_to 'Вход', new_user_session_path, class: 'navbar__item'

This results in writing a snippet for each menu item and, as a result, a huge amount of code, but I want to do something more compact so that the view takes 20-30 lines in size, not 120. My solution is to increase the level of abstraction by outputting specific links to an array and displaying links through iteration over the array. Roughly speaking something like this:
/ slim-lang
- links = [{ label: 'Events', path: root_path }, ... ]
- links.each do |link|
  li = link_to link[:label], link[:path], class: 'navbar__item'

But with this approach, there are still problems with conditional links. In general, after sitting for several hours with a spec rora, I came to the conclusion that I created the Navbar class, inside which I made the set of methods necessary for the navbar to display links, reduced all the code to a simple construction:
/ для верстки мне нужно было разбить список на 2 дива, так что передаваемые символы в метод нужны для поиска объектов
- @navbar.links(:root, :archive, :blog, :locale, :entry_group).each do |link|
  li = link_to link[:label], link[:path], class: 'navbar__item', **link[:options]

Inside the navbar:
class NavbarPresenter < BasePresenter
  include Rails.application.routes.url_helpers

  def links *args
    methods = args.select { |method| self.respond_to? method, :include_private and available_links.include? method }

    links = methods.map { |method| self.send method }

    links.flatten(1)
  end

private
  def format_link label, path, **args
    { label: label, path: path, options: args }
  end

  def available_links
    [:root, :archive, :blog, :locale, :entry_group]
  end

  def blog
    format_link I18n.t('header.items.blog'), posts_path
  end

  # ...
  # other links with different logic 
end

Works as I need it, no problem. But actually my questions are:
  1. What entity type is it? On the one hand, it has the logic of a presenter (in Ruby terminology), i.e. transforms the data in the way I need for the view, on the other hand, it does not have a model for representation, it has only a static data set defined in itself (ie, an array of links). Initially, I made it as NavbarPresenter, but now I have doubts
  2. Where can I initialize it? Now I declare it as a variable inside the application_controller @navbar = NavbarPresenter.new(view_context), but it is so available for all views, but I would like to make it available only inside the navbar (my navbar is partial)
  3. Where should I place it? The presenters? It seems to me that both the logic of the MenuLinks model and the logic of the presenter for such a model are executed inside it. Break it down into different entities? Is it acceptable to add a MenuLinks model that just defines a set of links for a navbar, or is that already silly?
  4. Is it reasonable to make classes in the same way to control the logic of different views? I understand that you can make normal and logical presenters for models, for example, for Event, User, etc., use them in views, but is it reasonable to do this for "static" entities that are not expected to change (at least often) and which don't have a model as such? Well, that is, I have made a complex slider, it has conditional logic, there are several constants (first slide index, max number of slides, slider id, etc.). If I wrote this in vue, I would never use "hardcoded" values ​​in the view, but would take them out to variables, to the store, anywhere except the view

If you think that I'm somehow fundamentally wrong about pop and you need to leave all this logic in the view - let me know, it will be useful for me to get an opinion from the outside.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
N
N. Bekseitov, 2019-03-29
@ned4ded

The links method has no place in the controller. Move the method to a separate helper or use the cells gem

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question