2009-07-02 11 views
76

Estoy escribiendo un contenedor personalizado para open_flash_chart plugin. Se coloca en /lib y lo carga como un módulo en ApplicationController.Rails/lib modules and

Sin embargo, tengo alguna clase de jerarquía o problema pequeño.

De cualquier controlador que pueda acceder open_flash_chart funciona como OpenFlashChart, etc Line

Sin embargo, en una clase en un módulo /lib, que no funciona!

¿Alguna idea?

Respuesta

143

Hay dos maneras de que los archivos se cargan en rieles:

  • Está registrada en el proceso de auto-carga, y hace referencia a una constante que corresponde al nombre del archivo. Por ejemplo, si tiene app/controllers/pages_controller.rb y PagesController de referencia, app/controllers/pages_controller.rb se cargará automáticamente. Esto sucede para una lista preestablecida de directorios en la ruta de carga. Esta es una característica de Rails, y no es parte del proceso normal de carga de Ruby.
  • Los archivos están explícitamente require d. Si un archivo es require d, Ruby busca en toda la lista de rutas en sus rutas de carga y encuentra el primer caso donde el archivo require d se encuentra en la ruta de carga. Puede ver toda la ruta de carga inspeccionando $ LOAD_PATH (un alias para $ :).

Desde lib es en su camino de carga, tiene dos opciones: o bien nombrar sus archivos con los mismos nombres que las constantes, por lo que los carriles cargará automáticamente hacia arriba cuando hace referencia a la constante de que se trate, o explícitamente requerir la módulo.

También noté que podría estar confundido acerca de otra cosa. ApplicationController es no el objeto raíz en el sistema. Observe:.

module MyModule 
    def im_awesome 
    puts "#{self} is so awesome" 
    end 
end 

class ApplicationController < ActionController::Base 
    include MyModule 
end 

class AnotherClass 
end 

AnotherClass.new.im_awesome 
# NoMethodError: undefined method `im_awesome' for #<AnotherClass:0x101208ad0> 

Usted tendrá que incluir el módulo en cualquier clase que desea utilizarlo en

class AnotherClass 
    include MyModule 
end 

AnotherClass.new.im_awesome 
# AnotherClass is so awesome 

Por supuesto, con el fin de poder incluir el módulo en el primer lugar, necesitarás tenerlo disponible (usando cualquiera de las técnicas anteriores).

+2

Sólo quería agregar: si uno de sus módulos en/lib (o en uno de los directorios de autocarga) ya está definido; Por ejemplo, si sobrecarga ActiveRecord o String, tendrá que solicitarlo explícitamente o no se cargará – Mike

+1

de manera extraña. Recibo: constante no inicializada GaClient (NameError), a menos que requiera 'ga_client' de antemano (la clase se define en lib/ga_client.rb). ¿Hay documentación para el esquema de nombres de carga automática? – mkirk

80

En Rails, los módulos 3/lib no se cargan automáticamente.

Esto es porque la línea:

# config.autoload_paths += %W(#{config.root}/extras) 

dentro config/application.rb se comenta.

Usted puede tratar de eliminar el comentario esta línea, o (funcionó aún mejor para mí), deje este comentadas (para referencia futura) y añadir dos líneas:

config.autoload_paths += %W(#{config.root}/lib) 
config.autoload_paths += Dir["#{config.root}/lib/**/"] 
+0

Esto duplicará la ruta '../ lib' en' ApplicationName :: Application.config.autoload_paths' array. – jibiel

+1

@jibiel, ¿cuál es la resolución aquí? – ylluminate

+0

no lo sé, pero esto funcionó bien ... :) – Orlando

19

lo que funcionó para mí, además descomentando config.autoload_paths (Estoy en Rails 3.1.3), era crear un inicializador de la siguiente manera:

#config/initializers/myapp_init.rb 
require 'my_module'  
include MyModule 

De esta manera puedo llamar a métodos mimodulo desde cualquier lugar y como métodos de clase Model.mymodule_method o como métodos de instancia mymodel.mymodule_method

Tal vez algunos expertos pueden explicar las implicaciones de esta. Por ahora, úsalo bajo tu propio riesgo.

Editar: Después, creo que una mejor approuch sería:

crear un inicializador de la siguiente manera:

#config/initializers/myapp_init.rb 
require ‘my_module’ 

incluir el módulo en caso necesario, de esta manera:

1) si desea utilizarlo como "Métodos de clase", use "extender":

class Myclass < ActiveRecord::Base 
    extend MyModule 
    def self.method1 
     Myclass.my_module_method 
    end 
end 

2) si desea utilizarlo como "Métodos de instancia" incluirlo dentro de la definición de clase:

class Myclass < ActiveRecord::Base 
include MyModule 
    def method1 
     self.my_module_method 
    end 
end 

3) recuerda que include MyModule se refiere a un archivo my_module.rb en su trayectoria de carga que debe ser necesario primero

+3

He creado mi módulo en la carpeta 'lib', por lo tanto, he agregado' config.autoload_paths + =% W (# {config.root}/lib) 'en el archivo' config/application.rb'. Después de eso, seguí tu sugerencia para agregar el archivo 'config/initializers/myapp_init.rb' y su contenido. Todo es bueno. Muchas gracias :) –

+0

Aunque 'require' funciona para mí y la carga automática no (método de módulo indefinido), [este comentario dice que no debe usar' require'] (http://stackoverflow.com/questions/ 3356742/best-way-to-load-module-class-from-lib-folder-in-rails-3 # comment3541227_3376401). – Dennis

0

Puede ser que desee cargar archivos explícitamente en el directorio lib en el momento de la inicialización de la aplicación.
En mi config/application.rb, tengo una entrada como,


También este podría ser el caso de que el nombre/jerarquía del módulo no sea el mismo que en el archivo o ubicación/nombre del archivo no es el mismo que esa jerarquía , por lo que la carga automática de ese archivo tampoco es posible. Así que cuando agregué una entrada en la parte inferior de config/application.rb como,
require "./lib/file_name_without_extention
funcionó bien.

2

Para utilizar el módulo lib/my_module.rb en sus modelos y controladores:

En config/application.rb:

config.watchable_dirs['lib'] = [:rb] 

En su modelo (idea similar para su controlador):

require_dependency 'my_module' 

class MyModel < ActiveRecord::Base 
    include MyModule 

    MyModule.some_method 
end 

este método es descrito en más detalle en http://hakunin.com/rails3-load-paths