Melhor maneira de carregar módulo / classe da pasta lib no Rails 3?

273

Como a versão mais recente do Rails 3 não carrega mais módulos e classes da lib, qual seria a melhor maneira de carregá-los?

No github:

A few changes were done in this commit:

Do not autoload code in *lib* for applications (now you need to explicitly 
require them). This makes an application behave closer to an engine 
(code in lib is still autoloaded for plugins);
Vincent
fonte

Respostas:

251

No Rails 2.3.9 , há uma configuração config/application.rbna qual você pode especificar diretórios que contêm os arquivos que você deseja carregar automaticamente.

Do application.rb:

# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
Slobodan Kovacevic
fonte
7
Observe a resposta de @ thankful também se você estiver procurando carregar automaticamente toda a subárvore de app/lib.
Tom Harrison
199
# Autoload lib/ folder including all subdirectories
config.autoload_paths += Dir["#{config.root}/lib/**/"]

Fonte: Rails 3 Dica rápida: carregamento automático do diretório lib, incluindo todos os subdiretórios, evite carregamento lento

Lembre-se de que os arquivos contidos na pasta lib são carregados apenas quando o servidor é iniciado. Se você deseja o conforto de carregar automaticamente esses arquivos, leia: Rails 3 Dica rápida: recarrega automaticamente as pastas lib no modo de desenvolvimento . Esteja ciente de que isso não se destina a um ambiente de produção, pois a recarga permanente diminui a velocidade da máquina.

grato
fonte
Os links estão mortos.
Besi
84

A mágica de carregar coisas automaticamente

Eu acho que a opção de controlar as pastas das quais o material de carregamento automático é realizado foi suficientemente abordada em outras respostas. No entanto, caso outra pessoa esteja tendo problemas com o carregamento de itens, apesar de os caminhos de carregamento automático terem sido modificados conforme necessário, essa resposta tenta explicar qual é a mágica por trás desse item de carregamento automático.

Portanto, quando se trata de carregar coisas de subdiretórios, há uma pegadinha ou uma convenção que você deve estar ciente. Às vezes, a magia Ruby / Rails (desta vez principalmente Rails) pode dificultar a compreensão de por que algo está acontecendo. Qualquer módulo declarado nos caminhos de carregamento automático será carregado apenas se o nome do módulo corresponder ao nome do diretório pai. Portanto, caso você tente colocar lib/my_stuff/bar.rbalgo como:

module Foo
  class Bar
  end
end

Não será carregado automaticamente. Então, novamente, se você mudar o nome do dir pai para foohospedagem, assim, o seu módulo no caminho: lib/foo/bar.rb. Estará lá para você. Outra opção é nomear o arquivo que você deseja carregar automaticamente pelo nome do módulo. Obviamente, só pode haver um arquivo com esse nome. Caso você precise dividir suas coisas em muitos arquivos, é claro que você poderia usar esse arquivo para exigir outros arquivos, mas eu não recomendo, porque quando no modo de desenvolvimento e você modifica esses outros arquivos, o Rails não consegue automagicamente recarregue-os para você. Mas se você realmente deseja, pode ter um arquivo com o nome do módulo que especifica os arquivos reais necessários para usar o módulo. Então você pode ter dois arquivos: lib/my_stuff/bar.rbe lib/my_stuff/foo.rbsendo o primeiro o mesmo que acima e o último contendo uma única linha:require "bar"e isso funcionaria da mesma forma.

PS Sinto-me compelido a acrescentar mais uma coisa importante. Ultimamente, sempre que eu quero ter algo no diretório lib que precisa ser carregado automaticamente, eu tendem a começar a pensar que se isso é algo que eu estou realmente desenvolvendo especificamente para este projeto (que geralmente é, pode ser que algum dia se transformar em um trecho de código "estático" usado em muitos projetos ou em um sub-módulo git, etc. nesse caso, ele definitivamente deve estar na pasta lib) e talvez seu lugar não esteja na pasta lib. Talvez deva estar em uma subpasta na pasta do aplicativo · Sinto que essa é a nova maneira de fazer trilhos. Obviamente, a mesma mágica está no trabalho, onde quer que você carregue automaticamente os caminhos em que coloca suas coisas, por isso é bom para essas coisas. Enfim, este é apenas o meu pensamento sobre o assunto. Você é livre para discordar. :)


ATUALIZAÇÃO: Sobre o tipo de mágica ..

Como severin apontou em seu comentário, o núcleo "mecanismo de carregamento automático de um módulo" certamente faz parte do Ruby, mas o material dos caminhos de carregamento automático não é. Você não precisa do Rails para fazerautoload :Foo, File.join(Rails.root, "lib", "my_stuff", "bar"). E quando você tentaria fazer referência ao módulo Foo pela primeira vez, ele seria carregado para você. No entanto, o que o Rails faz é fornecer uma maneira de tentar carregar coisas automaticamente de pastas registradas e isso foi implementado de tal maneira que ele precisa assumir algo sobre as convenções de nomenclatura. Se não tivesse sido implementado dessa maneira, toda vez que você fizer referência a algo que não está carregado no momento, precisará passar por todos os arquivos em todas as pastas de carregamento automático e verificar se algum deles contém o que você estava tentando fazer referência. Por sua vez, isso derrotaria a idéia de carregamento automático e carregamento automático. No entanto, com essas convenções em vigor, é possível deduzir do módulo / classe sua tentativa de carregar onde isso pode ser definido e apenas carregá-lo.

Timo
fonte
1
Por que isso é mágica em Ruby? O Ruby apenas fornece a função de carregamento automático do módulo #, que você pode usar para comandar o carregamento de um arquivo ao acessar uma constante (indefinida) (consulte ruby-doc.org/core-1.9.3/Module.html#method-i-autoload ). A correspondência dos nomes dos módulos / classes com os diretórios / arquivos é feita na minha opinião no Rails / ActiveSupport (por exemplo, aqui: github.com/rails/rails/blob/… ). Estou errado?
Severin
Sim, acredito que você está correto. Eu estava muito apressado para "corrigir" minha resposta original quando Zabba apontou sua "falha". Deixe-me atualizar um pouco mais a minha resposta para esclarecer esse problema.
Timo
1
Passei mais ou menos meia hora mexendo. Eu precisava (queria) de carregar automaticamente Sprockets :: JSRender :: Processor. O caminho para isso pode ser encontrado entrando no console do Rails e executando "Sprockets :: JSRender :: Processor" .underscore e desmentindo que se trata de "sprockets / js_render / processor" (com .rb adicionado) HTH alguém.
pedz
Você acabou de salvar minha sanidade. ~ profundo suspiro de alívio ~ muito obrigado por compartilhar :)
Brenden
Obrigado por este comentário mais útil. Não entendi por que alguns módulos estavam se comportando como antes de ler seu comentário. Bênçãos para você!
Mjnissim 31/05
41

Aviso: se você deseja carregar o 'patch de macaco' ou 'classe aberta' da pasta 'lib', não use a abordagem 'autoload' !!!

  • Abordagem " config.autoload_paths ": funciona apenas se você estiver carregando uma classe que foi definida apenas em UM local. Se alguma classe já foi definida em outro lugar, não será possível carregá-la novamente por essa abordagem.

  • Abordagem " config / initializer / load_rb_file.rb ": sempre funciona! qualquer que seja a classe de destino, seja uma nova classe ou uma "classe aberta" ou "patch de macaco" para a classe existente, ela sempre funciona!

Para obter mais detalhes, consulte: https://stackoverflow.com/a/6797707/445908

Siwei Shen 申思维
fonte
6
Esta é uma distinção crítica para entender. Obrigado por isso.
Tyler Collier
28

Muito parecido, mas acho que isso é um pouco mais elegante:

config.autoload_paths += Dir["#{config.root}/lib", "#{config.root}/lib/**/"]
Brian Armstrong
fonte
18

No meu caso, eu estava tentando simplesmente carregar um arquivo diretamente sob o diretório lib.

Dentro do application.rb ...

require '/lib/this_file.rb' 

não estava funcionando, mesmo no console e quando tentei

require './lib/this_file.rb' 

e trilhos carrega o arquivo perfeitamente.

Eu ainda sou muito noob e não sei por que isso funciona, mas funciona. Se alguém gostaria de me explicar, eu apreciaria: espero que isso ajude alguém de qualquer maneira.

Nick Res
fonte
2
Isso ocorre porque ./lib/this_file.rb procura no diretório atual (no console do Rails, isso seria sua raiz do Rails) e o /lib/this_file.rb procura isso como um caminho absoluto. Exemplo: ./lib/this_file.rb = /var/www/myrailsapp/lib/this_file.rb, /lib/this_file.rb = /lib/this_file.rb
Jason
7

Eu tive o mesmo problema. Aqui está como eu resolvi isso. A solução carrega o diretório lib e todos os subdiretórios (não apenas o direto). Claro que você pode usar isso para todos os diretórios.

# application.rb
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
hjuskewycz
fonte
5
Isso tem o efeito colateral desagradável das convenções de espaçamento de nomes do Rails totalmente irritantes. Se lib / bar / foo.rb, definindo Bar :: Foo, aparecer antes de lib / foo.rb, definindo Foo na pesquisa de carregamento automático, você receberá erros confusos, como Expected lib/bar/foo.rb to define constant Foose tentar carregar o lib / foo.rb consultando o Foo constante.
27413 Jacob
5

config.autoload_paths não funciona para mim. Eu resolvo de outra maneira

O Ruby on Rails 3 não recarrega automaticamente o código (carregamento automático) da pasta / lib. Eu resolvo colocando dentroApplicationController

Dir["lib/**/*.rb"].each do |path|
  require_dependency path
end 
msa.im
fonte
4

Se apenas determinados arquivos precisarem acessar os módulos na lib, basta adicionar uma instrução require aos arquivos que precisam. Por exemplo, se um modelo precisar acessar um módulo, adicione:

require 'mymodule'

na parte superior do arquivo model.rb.

Mike Fischer
fonte
50
Você não deve usar requiredentro de um aplicativo Rails, porque impede o ActiveSupport::Dependenciescarregamento [des] desse código corretamente. Em vez disso, você deve usar config.autoload_pathscomo a resposta acima e incluir / estender conforme necessário.
ben_h 4/08/10
13
Obrigado @Mike, eu estava indo fazer o que você fez, foi bom ver uma explicação do por que isso é ruim, obrigado por não remover a resposta.
pupeno
que tal incluir 'mymodule' se você apenas deseja carregar um módulo?
Mike
1
@ben_h Você não deve requirede nenhum lugar do aplicativo Rails? Em uma tarefa rake Atualmente estou requireing e includeing um módulo que vive em lib/. Eu não deveria estar fazendo isso?
Dennis
@ben_h Minha pesquisa revela que é comum ao requireseu lib/código (por exemplo, esta postagem no blog , esta resposta do SO ). Ainda não tenho certeza sobre a coisa toda. Você pode fornecer mais evidências por trás da reivindicação por não usar require?
Dennis
2

Soletre o nome do arquivo corretamente.

Seriamente. Eu lutei com uma classe por uma hora porque a classe era Governance :: ArchitectureBoard e o arquivo estava em lib / governança / architecture_baord.rb (O e A transpostos no "quadro")

Parece óbvio em retrospecto, mas foi o diabo que o localizou. Se a classe não estiver definida no arquivo em que o Rails espera que ela seja baseada na seleção do nome da classe, ela simplesmente não a encontrará.

David Hempy
fonte
2

A partir de Rails 5, recomenda-se colocar a pasta lib no diretório do aplicativo ou em vez criar outros espaços nome significativo para a pasta como services, presenters, featuresetc e colocá-lo no diretório app para carregamento automático por trilhos.

Por favor, verifique este link de discussão do GitHub também.

Ashik Salman
fonte