Plugins do Discourse e configuração/inicializadores do Rails 6: Pergunta

Olá, especialistas em plugins Discourse,

Uma pergunta rápida sobre plugins Discourse e inicializadores do Rails.

Se um plugin Discourse tiver um diretório chamado “config” e um subdiretório sob “config” chamado “initializers”, o aplicativo Rails do Discourse lê todos os arquivos de inicializador do plugin sob o diretório “initializers” como o Rails 6 faz?

A razão pela qual pergunto é que estou no meio da escrita de um aplicativo “back office” do Rails 6 (apenas Rails, sem EmberJS ou outro framework JS por cima) do zero para um cliente, e tenho um diretório sob initializers assim:

./config/initializers/client/

… e todos os inicializadores exclusivos do cliente estão no subdiretório “client”.

O Rails 6 lê todos os arquivos sob o diretório padrão de inicializadores (mesmo subdiretórios); e então eu estava me perguntando se os plugins Discourse, com uma estrutura de diretório semelhante para inicializadores, se comportarão como o Rails 6 e lerão todos os inicializadores no plugin de maneira assim:

./plugins/my_plugin/config/initializers/myclient/
      client_initializer1.rb
      client_initializer2.rb
      client_initializer2.rb

… sem registrar esses assets no arquivo plugin.rb?

Obrigado!

PS: Procurei em cerca de 10 plugins Discourse no GitHub e nenhum dos que vi tinha inicializadores sob o diretório config. Foi por isso que decidi postar a pergunta (e meu ambiente de desenvolvimento Rails não está configurado para o Discourse no momento, está tudo configurado para o cliente).

2 curtidas

Eu também gostaria de saber como o Plugin do Discourse difere de um Rails Engine comum. Eu estava apenas olhando o código-fonte, mas não entendi muito.

Depois de folhear esta página Ruby on Rails Guides: Configuring Rails Applications, acho que plugin.rb é meio que a mesma coisa. A maioria dos plugins de tamanho considerável o usa como ponto de entrada para a lógica, em vez da lógica em si.

Sim, tenho lido bastante esse guia do Rails ultimamente. Basicamente, estou “ok” com o funcionamento da configuração do Rails 6 (ainda estou aprendendo, mas ficando cada vez mais confortável a cada dia).

Estou apenas me perguntando se podemos usar a mesma estrutura em um plugin do Discourse (para inicializadores), se o Rails lerá os inicializadores nos subdiretórios como faz no Rails 6; ou se precisamos registrar o diretório de inicializadores do plugin como um “ativo” de configuração (por falta de uma palavra melhor) no plugin.rb.

Ontem estive estudando os plugins do Rails e fazendo algumas comparações também.

O Discourse não lê nenhum arquivo Ruby além do plugin.rb, pelo que sei. Ele lê os arquivos JS e de configuração. Todos os arquivos Ruby precisam ser requiredos no plugin.rb.

3 curtidas

Eu também acredito nisso.

Você carrega quaisquer arquivos Ruby adicionais de que precisa dentro do plugin.rb.

Aqui está um exemplo do plugin Follow:

1 curtida

Essa é mais ou menos a minha impressão ao ler vários plugins do Discourse no GitHub.

Parece que o Discourse só lê o plugin.rb e precisamos carregar todos os outros arquivos Ruby que possamos querer, como inicializadores, no plugin.rb.

No entanto, eu esperava estar errado e que pudesse haver uma integração “mais profunda” entre os plugins do Discourse e o Rails; pois tenho me acostumado muito com o quão ótimo é o Rails 6.

Obrigado por confirmar também.

1 curtida

Acho que deveria haver uma maneira de exigir código de inicialização no plugin.rb também.
Você tentou isso no plugin.rb?

Rails.application.config.before_initialize do
  # o código de inicialização vai aqui
end

Sim, não há problema em chamar e carregar os inicializadores no plugin.rb.

A razão da minha pergunta é que estou atualmente escrevendo um aplicativo Rails 6 bastante grande para uma empresa, convertendo seus scripts legados de back-office (de várias décadas) em um aplicativo Rails. Para adicionar inicializadores, basta ter um subdiretório em config/initializers (no Rails) e todos os meus arquivos de inicialização são incluídos tão bem, sem necessidade de escrever qualquer código para incluí-los no Rails.

Obrigado por todas as respostas. Muito apreciado!

1 curtida

Sim, adoraria ver esses recursos do Rails sendo portados para plugins do Discourse. Um dos meus favoritos pessoais seria poder recarregar os arquivos Ruby em tempo real sem precisar reiniciar o servidor.

1 curtida

É para isso que serve o reloadable_patch. Se você envolver alterações de classes Ruby em reloadable_patch, elas devem ser recarregadas ao vivo!

1 curtida

Posso envolver todo o arquivo plugin.rb nele para desenvolvimento? Mais seriamente, até onde podemos ir com isso?

Além disso, adicionar novos arquivos ou alterar qualquer arquivo yml requer reiniciar o servidor, certo?

2 curtidas

Você não deveria ter que fazer um reloadable_patch para tudo. Muitos dos métodos definidos em instance.rb para facilitar o desenvolvimento de plugins usam reloadable_patch internamente, como o add_to_serializer.

Idealmente, nossa API de plugins é boa o suficiente para que você não precise fazer uma quantidade insana de reloadable_patch.

Sim, isso é verdade. Eu me pergunto se algo pode ser feito em relação às alterações nos arquivos yml; isso me incomoda pessoalmente.

3 curtidas

Verdade. Eu não sabia que reloadable_patch era destinado a suportar o recarregamento ao vivo. Posso pensar em muitos casos de uso além daqueles em que o Discourse já o utiliza. Ou seja:

reloadable_patch do
 require 'x/y/z'
end

ou patches de macaco.

1 curtida

Acho que remover ou adicionar uma função dessas ainda seria problemático, pois o reloadable_patch é chamado dentro da função.

De qualquer forma, isso ajuda bastante.

1 curtida

Comecei a investigar a atualização em tempo real de alterações em arquivos YAML, e isso realmente funciona. Plugins podem quebrar essa atualização em tempo real se não estiverem usando corretamente o reloadable_patch, mas assim que todos os seus plugins puderem recarregar com segurança, suas alterações em YAML também o farão.

4 curtidas

Seria super útil, no entanto, se você pudesse descrever os passos exatos para usar o reloadable patch.

Aqui está o que tentei, sem muito sucesso (com certeza estou perdendo algo):

after_initialize do
    add_to_serializer(:topic_view, :check, false) do
        puts 'nocheck'
    end
end

Assim que o servidor inicia, e eu altero nocheck para check, ele ainda imprime nocheck depois que eu recarrego a rota do tópico.

after_initialize do
    reloadable_patch do |plugin|
        puts 'nocheck'
    end
end

Ainda sem sucesso ao recarregar qualquer página após alterar a string dentro do puts.

Acho que te levei a um erro nos posts acima. reloadable_patch é útil para o desenvolvimento do Discourse, mas @david explicou muito bem seu uso:


Qualquer coisa dentro do bloco after_initialize do plugin.rb é carregada apenas durante a inicialização da aplicação, e não nas recargas subsequentes.

Então, supondo que você queira adicionar algo ao serializador de usuário. O comportamento normal seria assim:

Na inicialização:

  • O Discourse carrega user_serializer.rb
  • O Discourse carrega plugin.rb, que tem uma sobrescrita para user_serializer

Na recarga:

  • O Discourse recarrega user_serializer.rb
  • (o patch do plugin.rb não é recarregado, a sobrescrita do plugin é perdida)

Com nosso sistema reloadable_patch:

Na inicialização:

  • O Discourse carrega user_serializer.rb
  • O Discourse carrega plugin.rb e registra o reloadable_patch para o serializador de usuário
  • Os patches recarregáveis são executados

Na recarga:

  • O Discourse recarrega user_serializer.rb
  • Os patches recarregáveis são executados
  • (uau, a sobrescrita do plugin ainda está funcionando)
6 curtidas

Isso descreve uma propriedade central do Rails, que não é específica do Discourse.

No Rails, todos os inicializadores são carregados apenas quando o Rails inicia, então qualquer plugin que execute código com base no inicializador, como “after_initializer”, será executado apenas na inicialização ou reinicialização do Rails (por favor, me corrija se estiver errado).

A razão pela qual estou familiarizado com isso é que estou atualmente construindo uma aplicação Rails para um cliente e escrevi muitos inicializadores para várias tarefas (booleans, arrays estáticos, etc.). Em cada caso, se alterarmos qualquer código em um inicializador do Rails, é necessário reiniciar o Rails (“Control c, rails s no dev”) para que os novos valores nos inicializadores sejam carregados na aplicação Rails.

Por favor, me corrijam se eu estiver errado! Obrigado.

Às vezes, acho que pode ser um pouco confuso para alguns desenvolvedores de plugins do Discourse, especialmente aqueles que trabalham principalmente com plugins do Discourse e não com aplicações Rails em geral, quando escrevemos “O Discourse faz isso” ou “O Discourse faz aquilo”, quando o que realmente estamos descrevendo é uma função ou propriedade central do Rails, não necessariamente específica do Discourse.

O Rails 6 lê todos os arquivos no diretório config/initializers (e todos os subdiretórios config/initializers) apenas quando o Rails inicia. Da mesma forma (não tenho 100% de certeza sobre plugins), um plugin do Discourse com código dependente de after_initialize será (por favor, confirme alguém?) carregado pela aplicação Rails apenas quando o Rails iniciar ou reiniciar, pois essa é uma propriedade fundamental do processo de inicialização do Rails.

Minha suposição é que todos aqui que trabalham com Rails já sabem disso. Estou apenas começando a conhecer esses detalhes (e sinto que tenho um longo caminho a percorrer para me tornar um especialista); porque estou trabalhando em uma aplicação Rails todos os dias (nestes dias), o que, a propósito, agora gostaria de ter começado a trabalhar com Rails há uma década, pois vindo de uma experiência com desenvolvimento LAMP, acho o Rails muito melhor (fácil e divertido de trabalhar).

Tornei-me um grande fã do Rails este ano e sou muito grato ao Discourse por me colocar nesse caminho.

Novamente, por favor, me corrijam se eu estiver errado! Obrigado. Estou tentando me tornar mais especialista em Rails.

6 curtidas

Sim! Isso está correto, assim como sua compreensão dos inicializadores do Rails.

Eu também sou um grande fã do Rails :slight_smile:

7 curtidas