Tự động tải các tập tin lib trong Rails 4


229

Tôi sử dụng dòng sau trong trình khởi tạo để tự động tải mã trong /libthư mục của mình trong quá trình phát triển:

cấu hình / khởi tạo / custom.rb:

RELOAD_LIBS = Dir[Rails.root + 'lib/**/*.rb'] if Rails.env.development?

(từ Rails 3 Quicktip: Tự động tải lại các thư mục lib trong chế độ phát triển )

Nó hoạt động rất tốt, nhưng nó quá kém hiệu quả để sử dụng trong sản xuất - Thay vì tải lib trên mỗi yêu cầu, tôi chỉ muốn tải chúng khi khởi động. Cùng một blog có một bài viết khác mô tả cách làm điều này:

cấu hình / ứng dụng.rb:

# Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]

Tuy nhiên, khi tôi chuyển sang điều đó, ngay cả khi đang phát triển, tôi nhận được NoMethodErrors khi cố gắng sử dụng các hàm lib.

Ví dụ về một trong các tệp lib của tôi:

lib / extend.rb:

Time.class_eval do
  def self.milli_stamp
    Time.now.strftime('%Y%m%d%H%M%S%L').to_i
  end
end

Gọi Time.milli_stampsẽ ném NoMethodError

Tôi nhận ra những người khác đã trả lời các câu hỏi tương tự trên SO nhưng tất cả họ dường như đều giải quyết các quy ước đặt tên và các vấn đề khác mà tôi không phải lo lắng trước đây - Các lớp lib của tôi đã hoạt động để tải theo yêu cầu, tôi chỉ muốn thay đổi nó để tải mỗi lần khởi động . Cách đúng đắn để làm điều này là gì?


Thư mục cấu hình / khởi tạo có được tự động tải khi ứng dụng Rails khởi động không?
Jwan622

Câu trả lời:


548

Tôi nghĩ rằng điều này có thể giải quyết vấn đề của bạn:

  1. trong cấu hình / application.rb :

    config.autoload_paths << Rails.root.join('lib')

    và giữ quy ước đặt tên đúng trong lib .

    trong lib / foo.rb :

    class Foo
    end

    trong lib / foo / bar.rb :

    class Foo::Bar
    end
  2. nếu bạn thực sự muốn thực hiện một số bản vá khỉ trong tệp như lib / extend.rb , bạn có thể yêu cầu nó theo cách thủ công:

    trong cấu hình / khởi tạo / Yêu cầu.rb :

    require "#{Rails.root}/lib/extensions" 

PS


1
@ ifyouseewendy- Bạn hoàn toàn đúng - vì phần mở rộng.rb không tuân theo các quy ước đặt tên Rails, Rails sẽ không bao gồm nó trong quá trình tải. Tôi đã làm cho nó hoạt động bằng cách yêu cầu nó bằng tay.
Yarin

@ifyouseewendy làm thế nào tôi có thể bao gồm các tập tin trước khi các mô hình được tải? thêm đường dẫn để tự động tải nó thật tuyệt, nhưng làm thế nào để kiểm soát thứ tự bao gồm? thx
Ma trận

@Matrix "bao gồm các tệp trước khi các mô hình được tải", bạn có thể yêu cầu tệp của mình theo cách thủ công mà không cần sử dụng tính năng tự động tải.
ifyouseewendy

@ifyouseewendy nếu tôi yêu cầu nó trong trình khởi tạo nhưng tệp nằm trong autoload_path, nó sẽ được tải lại (tải 2 lần) hay không? Theire là một "allow_once" như trong php?
Ma trận

5
Điều này dường như không hoạt động trong API Rails 5 trong sản xuất (nhưng không phát triển). Tôi tin rằng bạn cần sử dụng config.eager_load_paths << Rails.root.join('lib'). Tuy nhiên, điều đó cũng có một nhược điểm lớn trong việc eager_load_pathstải mọi thứ trong các nhiệm vụ. Tôi nghĩ rằng giải pháp của lulalala là tốt hơn. Đây là một bài đăng blog với nhiều chi tiết hơn: blog.arkency.com/2014/11/ Cách
hirowatari

33

Mặc dù điều này không trực tiếp trả lời câu hỏi, nhưng tôi nghĩ rằng nó là một lựa chọn tốt để tránh câu hỏi hoàn toàn.

Để tránh tất cả autoload_pathshoặc eager_load_pathsrắc rối, hãy tạo thư mục "lib" hoặc "misc" trong thư mục "ứng dụng". Đặt mã như bạn thường làm trong đó và Rails sẽ tải các tệp giống như cách nó sẽ tải (và tải lại) các tệp mô hình.


3
Tôi đang ở Rails 4.2. và nó không tự động tải các tệp bên dưới app, tôi cần thực hiện thủ công ...... hoặc cần đặt nó vào đường dẫn tự động tải ..
Arup Rakshit

6
Bạn đang sai, Arup, bất kỳ thư mục con của thư mục ứng dụng sẽ được tự động trong mảng autoload_paths trong Rails 4.2.See edgeguides.rubyonrails.org/...
Dr.Strangelove

Ngoại trừ app/viewsthư mục không được thêm vào; hay đúng hơn là được loại bỏ rõ ràng.
James B. Byrne

1
Câu trả lời chính xác. Chỉ có điều làm việc cho tôi trên đường ray 5 / api.
jstafford

6
Chỉ cần nhớ điều đó libcó nghĩa là mã có thể được áp dụng cho nhiều dự án và có thể có thể được trích xuất thành đá quý. Nếu không tạo một thư mục phù hợp hơn trong tìm kiếm ứng dụng services/, hoặc presenters/thậm chí cả các thư mục con này.
PhilT

6

Điều này có thể giúp một người như tôi tìm thấy câu trả lời này khi tìm kiếm giải pháp cho cách Rails xử lý việc tải lớp ... Tôi thấy rằng tôi phải xác định moduletên có tên trùng khớp với tên tệp của mình, thay vì chỉ xác định một lớp:

Trong tệp lib / Development_mail_interceptor.rb (Có, tôi đang sử dụng mã từ Railscast :))

module DevelopmentMailInterceptor
  class DevelopmentMailInterceptor
    def self.delivering_email(message)
      message.subject = "intercepted for: #{message.to} #{message.subject}"
      message.to = "myemail@mydomain.org"
    end
  end
end

hoạt động, nhưng nó không tải nếu tôi không đặt lớp bên trong một mô-đun.


1
Trong ruby ​​"khớp một cách thích hợp" có nghĩa là tệp được đặt trong hệ thống tệp tại LOAD_PATH/module/class.rb(dưới mức) LOAD_PATHtrong đường dẫn tải được sử dụng bởi ứng dụng Ruby (autoload_paths trong trường hợp Rails). libđã dao động từ việc được Rails tự động tải sang không được tự động tải và trong các phiên bản gần đây (> = Rails 3.x), nó không được tự động tải. Bất cứ điều gì kỳ diệu đang làm cho công việc này cho bạn không được khuyến khích. Có lẽ đó là một Railscast cũ?
Peter H. Boling

0

Sử dụng config.to_prepare để tải cho bạn các bản vá / tiện ích mở rộng cho mọi yêu cầu trong chế độ phát triển.

config.to_prepare do |action_dispatcher|
 # More importantly, will run upon every request in development, but only once (during boot-up) in production and test.
 Rails.logger.info "\n--- Loading extensions for #{self.class} "
 Dir.glob("#{Rails.root}/lib/extensions/**/*.rb").sort.each do |entry|
   Rails.logger.info "Loading extension(s): #{entry}"
   require_dependency "#{entry}"
 end
 Rails.logger.info "--- Loaded extensions for #{self.class}\n"

kết thúc

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.