October 22, 2024
Chicago 12, Melborne City, USA
javascript

How to create a tab where each tab renders a different controller?


I have a tab where the first tab renders the devise controller (edit.html.erb view) and the second one I want to render the ChartsController. How can I do this in Rails 7? My code:

edit.html.erb:

<div class="bg-white p-8">
  <div class="tab-section rounded-lg min-h-[400px]">
    <div class="flex flex-wrap gap-1 border-b border-stone-300">
      <button class="inline-block p-4 text-stone-600 font-semibold rounded-t-lg active"
        data-tab-target="#tab1">Editar Perfil</button>
      <button class="inline-block p-4 text-stone-600 font-semibold rounded-t-lg active"
        data-tab-target="#tab2">Estatística </button>
    </div>
    <div class="mt-4">
      <div id="tab1" class="tab-content text-gray-700">
        <div class="flex">
          <aside class="card bg-white border border-gray-300 rounded-lg text-center justify-center flex flex-col items-center w-1/3">
            <% if resource.avatar? %>
              <img src="<%= resource.avatar %>" alt="Avatar" class="rounded-full border-yellow-500 border-4 border-secondary w-72 h-72 mb-4" />
            <% else %>
              <%= lucide_icon('user-round', class: "rounded-full border-yellow-500 border-4 border-secondary w-72 h-72 mb-4") %>
            <% end %>
            <h2 class="text-2xl font-semibold mb-4"><%= resource.name %></h2>
            <p class="text-lg">
              Quantidade de horas que trabalha na semana: <br />
              <strong class="text-4xl"><%= resource.formatted_hours_per_week %></strong>
            </p>
            <br />
            <p class="text-lg">
              Tempo restante do compromisso: <br />
              <strong class="text-4xl"><%= resource.commitments.last.time_remaining if resource.commitments.any? %></strong>
            </p>
          </aside>  
          <main class="flex-1 p-4">
            <%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put, class: 'space-y-4' }) do |f| %>
              <%= render "devise/shared/error_messages", resource: resource %>

              <div class="field">
                <%= f.label :name, "Nome", class: 'block font-semibold' %>
                <%= f.text_field :name, class: 'mt-1 block w-full border border-gray-300 rounded-md p-2', placeholder: "Seu nome" %>
              </div>

              <div class="field">
                <%= f.label :email, class: 'block font-semibold' %>
                <%= f.email_field :email, autofocus: true, autocomplete: "email", class: 'mt-1 block w-full border border-gray-300 rounded-md p-2', placeholder: "Seu email" %>
              </div>

              <div class="field">
                <%= f.label :avatar, class: 'block font-semibold' %>
                <%= f.url_field :avatar, class: 'mt-1 block w-full border border-gray-300 rounded-md p-2', placeholder: "URL da imagem (ex: https://github.com/eltonsantos.png)" %>
              </div>

              <div class="field">
                <%= f.label :hours_per_week, "Horas por semana", class: 'block font-semibold' %>
                <%= f.number_field :hours_per_week, step: 0.25, class: 'mt-1 block w-full border border-gray-300 rounded-md p-2', placeholder: "Quantidade de horas trabalhadas por semana" %>
              </div>

              <div class="field">
                <%= f.label :password, "Senha", class: 'block font-semibold' %>
                <%= f.password_field :password, autocomplete: "new-password", class: 'mt-1 block w-full border border-gray-300 rounded-md p-2', placeholder: "Nova senha (deixe em branco para não alterar)" %>
              </div>

              <div class="field">
                <%= f.label :password_confirmation, "Confirmação de senha", class: 'block font-semibold' %>
                <%= f.password_field :password_confirmation, autocomplete: "new-password", class: 'mt-1 block w-full border border-gray-300 rounded-md p-2', placeholder: "Confirme a nova senha" %>
              </div>

              <div class="field">
                <%= f.label :current_password, "Senha atual", class: 'block font-semibold' %>
                <%= f.password_field :current_password, autocomplete: "current-password", class: 'mt-1 block w-full border border-gray-300 rounded-md p-2', placeholder: "Senha atual" %>
              </div>

              <div class="actions mt-4">
                <%= f.submit "Atualizar", class: 'bg-blue-600 text-white font-semibold py-2 px-4 rounded' %>
              </div>
            <% end %>

            <h3 class="text-lg font-semibold mt-6 border-t-4 border-red-400">Zona de perigo</h3>
            <div>
              <%= button_to registration_path(resource_name), data: { confirm: "Você tem certeza? Essa ação não poderá ser desfeita e todos os dados serão perdidos!" }, method: :delete, class: 'button orange mt-3 inline-flex items-center bg-red-500 text-white px-4 py-2 rounded hover:bg-red-600 font-bold' do %>
                <span class="mr-2">
                  <%= lucide_icon('x', class: 'text-white') %>
                </span>
                Cancelar minha conta
              <% end %>
            </div>
          </main>
        </div>
      </div>
      <div id="tab2" class="hidden tab-content text-gray-700">
        <h4 class="font-bold mt-9 mb-4 text-2xl">Estatística</h4>
        <%= render partial: 'charts/index', locals: { tarefa: Task.first } %>
      </div>
    </div>
  </div>
</div>

<script>
  const tabs = document.querySelectorAll('[data-tab-target]');
  const activeClass="text-stone-900";

  tabs[0].classList.add(activeClass);
  document.querySelector('#tab1').classList.remove('hidden');

  tabs.forEach(tab => {
    tab.addEventListener('click', () => {
      const targetContent = document.querySelector(tab.dataset.tabTarget);

      document.querySelectorAll('.tab-content').forEach(content => content.classList.add('hidden'));
      targetContent.classList.remove('hidden');

      document.querySelectorAll('.text-stone-900').forEach(activeTab => activeTab.classList.remove(activeClass));

      console.log(tab)
      tab.classList.add(activeClass);
    });
  });
</script>

The first tab is DeviseController, and the second is it:

class ChartsController < ApplicationController
  def index
  end
end

My second view:
/app/views/charts/_index.html.erb:

<h2>Conteúdo da Segunda Aba</h2>
<p>Esta é a view renderizada pelo ChartsController.</p>

<%= tarefa.title %>
<%= tarefa.description %>
<%= tarefa.category.name %>
<%= tarefa.hours %>

I don’t know if I explained everything correctly, but it’s something simple, I just have a tab, which has 2 tabs, so when I access the page, the first selected tab renders the DeviseController#edit, when I click on the second, I need it to render the ChartsController#index, that’s all. However, I’ve tried everything, I asked the gpt chat, Claude and none of them helped me.



You need to sign in to view this answers

Leave feedback about this

  • Quality
  • Price
  • Service

PROS

+
Add Field

CONS

+
Add Field
Choose Image
Choose Video