ruby-on-rails - rails where to put modules
Módulos Rails/lib y (5)
Estoy escribiendo un contenedor personalizado para el complemento open_flash_chart
. Se coloca en /lib
y se carga como un módulo en ApplicationController
.
Sin embargo, tengo alguna jerarquía de clases o un pequeño problema.
Desde cualquier controlador, puedo acceder a open_flash_chart
funciones de OpenFlashChart
como OpenFlashChart
, Line
, etc.
Sin embargo, en una clase en un módulo /lib
, ¡no funciona!
¿Algunas ideas?
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 de config / application.rb se comenta.
Puede intentar descomentar esta línea o, (funcionó incluso mejor para mí), deje esto comentado (para referencia futura) y agregue estas dos líneas:
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
Hay dos formas en que los archivos se cargan en Rails:
- Se registra en el proceso de autocarga y hace referencia a una constante que corresponde al nombre del archivo. Por ejemplo, si tiene
app/controllers/pages_controller.rb
y hace referencia a PagesController, laapp/controllers/pages_controller.rb
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 son explícitamente
require
d. Si serequire
un archivo d, Ruby busca en toda la lista de rutas en sus rutas de carga y encuentra el primer caso donde el archivo querequire
d está en la ruta de carga. Puede ver toda la ruta de carga inspeccionando $ LOAD_PATH (un alias para $ :).
Como lib
está en su ruta de carga, tiene dos opciones: o bien, nombre sus archivos con los mismos nombres que las constantes, de modo que Rails los recoja automáticamente cuando haga referencia a la constante en cuestión o exija explícitamente el módulo.
También noto que podrías estar confundido acerca de otra cosa. ApplicationController no es el objeto raíz en el sistema. Observar:
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>
Deberá incluir el módulo en la clase en la que desee usarlo.
class AnotherClass
include MyModule
end
AnotherClass.new.im_awesome
# AnotherClass is so awesome
Por supuesto, para poder incluir el módulo en primer lugar, deberá tenerlo disponible (utilizando cualquiera de las técnicas anteriores).
Lo que funcionó para mí, además de descomentar config.autoload_paths (I''m on Rails 3.1.3), fue crear un inicializador como este:
#config/initializers/myapp_init.rb
require ''my_module''
include MyModule
De esta forma puedo llamar a los métodos de mymodule desde cualquier lugar y como métodos de clase Model.mymodule_method
o como métodos de instancia mymodel.mymodule_method
Quizás algún experto pueda explicar las implicaciones de esto. Por ahora, úsalo bajo tu propio riesgo.
Editar: Después, creo que una mejor aplicación sería:
crea un inicializador como este:
#config/initializers/myapp_init.rb
require ‘my_module’
Incluya el módulo donde sea necesario, como este:
1) si desea usarlo 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 usarlo como "Métodos de instancia", inclúyalo dentro de la definición de Clase:
class Myclass < ActiveRecord::Base
include MyModule
def method1
self.my_module_method
end
end
3) recuerde que include MyModule
refiere a un archivo my_module.rb
en su ruta de carga que primero debe ser requerido
Para usar 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 se describe con más detalle en http://hakunin.com/rails3-load-paths
Puede ser que desee cargar archivos de manera explícita en el directorio lib en el momento de la inicialización de la aplicación.
En mi config / application.rb, tengo una entrada como,
config.autoload_paths += %W(#{config.root}/lib)
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 la ubicación / nombre del archivo no es lo mismo que esa jerarquía, por lo que tampoco es posible la carga automática de ese archivo. Entonces cuando agregué una entrada en la parte inferior de config / application.rb como,
require "./lib/file_name_without_extention
funcionó bien