Рейки / модулі lib та


83

Я пишу спеціальну обгортку для open_flash_chartплагіна. Він розміщений в /libі завантажений як модуль в ApplicationController.

Однак у мене є якась ієрархія класу або щось інше.

З будь-якого контролера я можу отримати доступ до open_flash_chartфункцій, як OpenFlashChartі Lineт.д.

Однак у класі в /libмодулі це не працює!

Будь-які ідеї?


сподіваюся , що це може допомогти вам stackoverflow.com/questions/17304110 / ...
S.Yadav

Відповіді:


147

Існує два способи завантаження файлів у Rails:

  • Він реєструється в процесі автозавантаження, і ви посилаєтесь на константу, яка відповідає імені файлу. Наприклад, якщо у вас є app/controllers/pages_controller.rbпосилання на PagesController, воно app/controllers/pages_controller.rbбуде автоматично завантажено. Це відбувається для попередньо встановленого списку каталогів на шляху завантаження. Це особливість Rails і не є частиною звичайного процесу завантаження Ruby.
  • Файли явно required. Якщо файл має значення required, Ruby переглядає весь список шляхів у ваших шляхах завантаження та знаходить перший випадок, коли файл, який ви requireзнаходитесь, знаходиться у шляху завантаження. Ви можете побачити весь шлях завантаження, перевіривши $ LOAD_PATH (псевдонім для $ :).

Оскільки libу вашому шляху завантаження, у вас є два варіанти: або назвати файли з тими самими іменами, що і константи, тому Rails автоматично підбере їх, коли ви посилаєтесь на константу, про яку йде мова, або явно вимагає модуль.

Я також помічаю, що вас може сплутати інша річ. ApplicationController не є кореневим об’єктом у системі. Дотримуйтесь:

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>

Вам потрібно буде включити модуль до будь-якого класу, в якому ви хочете його використовувати.

class AnotherClass
  include MyModule
end

AnotherClass.new.im_awesome
# AnotherClass is so awesome

Звичайно, для того, щоб мати можливість включити модуль в першу чергу, вам потрібно мати його в наявності (використовуючи будь-який із наведених вище методів).


2
Просто хотів додати: якщо один із ваших модулів у / lib (або в одному з каталогів автозавантаження) вже визначений; наприклад, ви перевантажуєте ActiveRecord або String, вам потрібно буде це явно вимагати, інакше він не буде завантажений
Mike

1
дивно, я отримую: неініціалізовану константу GaClient (NameError), якщо я не вимагаю заздалегідь 'ga_client' (клас визначений у lib / ga_client.rb). Чи існує документація для схеми імен автозавантаження?
mkirk

87

У Rails 3 / lib модулі не завантажуються автоматично.

Це тому, що рядок:

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

всередині config / application.rb коментується.

Ви можете спробувати прокоментувати цей рядок або ((мені це вдалося навіть краще), залишити цей коментар (для подальшого використання) і додати ці два рядки:

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

Це повторить ../libшлях у ApplicationName::Application.config.autoload_pathsмасиві.
jibiel

1
@jibiel, то яка тут роздільна здатність?
ілюмінація

4
чому останній варіант для вас працював краще? Крім того, чому було змінено за замовчуванням ... повинна бути причина, незважаючи на те, що багато людей знаходять роботу.
ckarbass

@ylluminate Отже, одиночного config.autoload_paths += Dir["#{config.root}/lib/**/"]має бути достатньо. @ckarbass Другий рядок дає вам свободу впорядковувати свої утиліти у підпапки і таким чином поєднувати ваші модулі з просторами імен . Це майже все. І ось чому було змінено значення за замовчуванням. Краще пізно, ніж ніколи :)
jibiel

Це здається мені трохи безладно. Чи не буде це зайвим чином автоматично завантажувати граблі?
Денніс

22

У мене, крім розкоментування config.autoload_paths (я на Rails 3.1.3), мені вдалося створити такий ініціалізатор:

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

Таким чином я можу викликати методи mymodule з будь-якого місця і як методи класуModel.mymodule_method або як методи екземпляраmymodel.mymodule_method

Можливо, якийсь експерт може пояснити наслідки цього. На даний момент використовуйте його на свій страх і ризик.

Редагувати: Згодом, я думаю, кращою програмою буде:

створити такий ініціалізатор:

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

Включіть модуль, де це потрібно, наприклад:

1) якщо ви хочете використовувати його як "Методи класів", використовуйте "розширити":

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

2) якщо ви хочете використовувати його як "Методи екземпляру", включіть його до визначення класу:

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

3) пам’ятайте, що include MyModuleпосилається на файл my_module.rbу вашому шляху завантаження, який потрібно спочатку вимагати


3
Я створив свій модуль у libпапці, тому додав config.autoload_paths += %W(#{config.root}/lib)у config/application.rbфайл. Після цього я виконав вашу пропозицію щодо додавання config/initializers/myapp_init.rbфайлу та його вмісту. Все добре. Велике спасибі :)
SMMousavi

Незважаючи на те, що requireу мене це працює, а автоматичне завантаження ні (не визначений метод модуля), цей коментар говорить, що ви не повинні використовуватиrequire .
Денніс

3

Щоб використовувати модуль lib/my_module.rbу своїх моделях та контролерах:

В config/application.rb:

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

У вашій моделі (подібна ідея для вашого контролера):

require_dependency 'my_module'

class MyModel < ActiveRecord::Base
  include MyModule

  MyModule.some_method
end

Цей метод більш докладно описаний на http://hakunin.com/rails3-load-paths


0

Можливо, ви хочете явно завантажити файли в каталог lib під час ініціалізації програми.
У моєму config / application.rb у мене є запис як,
config.autoload_paths += %W(#{config.root}/lib)

Також це може бути так, що ім'я / ієрархія модуля не збігається з файлом або розташування / ім'я файлу не збігається з цією ієрархією, тому автозавантаження цього файлу також неможливо. Отже, коли я додав запис внизу config / application.rb as,
require "./lib/file_name_without_extention
він працював нормально.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.