Cách tốt nhất để tải mô-đun / lớp từ thư mục lib trong Rails 3?


273

Vì bản phát hành Rails 3 mới nhất không còn tự động tải các mô-đun và lớp từ lib nữa, nên cách tốt nhất để tải chúng là gì?

Từ 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);

Câu trả lời:


250

Kể từ Rails 2.3.9 , có một cài đặt config/application.rbtrong đó bạn có thể chỉ định các thư mục chứa các tệp bạn muốn tự động tải.

Từ ứng dụng.rb:

# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)

7
Lưu ý @ câu trả lời cũng biết nếu bạn đang muốn tự động tải toàn bộ cây con của app/lib.
Tom Harrison

199
# Autoload lib/ folder including all subdirectories
config.autoload_paths += Dir["#{config.root}/lib/**/"]

Nguồn: Rails 3 Quicktip: Tự động tải thư mục lib bao gồm tất cả các thư mục con, tránh tải lười biếng

Xin lưu ý rằng các tệp có trong thư mục lib chỉ được tải khi máy chủ được khởi động. Nếu bạn muốn thoải mái tự động tải các tệp đó, hãy đọc: Rails 3 Quicktip: Tự động tải lại các thư mục lib trong chế độ phát triển . Xin lưu ý rằng điều này không có nghĩa đối với môi trường sản xuất vì việc tải lại vĩnh viễn làm chậm máy.


Các liên kết đã chết
Besi

84

Sự kỳ diệu của công cụ tự động tải

Tôi nghĩ rằng tùy chọn kiểm soát các thư mục mà công cụ tự động tải được thực hiện đã được bao phủ đầy đủ trong các câu trả lời khác. Tuy nhiên, trong trường hợp người khác gặp sự cố tải nội dung mặc dù họ đã sửa đổi đường dẫn tự động tải theo yêu cầu, thì câu trả lời này cố gắng giải thích điều kỳ diệu đằng sau thứ tự động tải này.

Vì vậy, khi nói đến việc tải nội dung từ các thư mục con, có một hình ảnh xác thực hoặc quy ước bạn nên biết. Đôi khi phép thuật Ruby / Rails (lần này chủ yếu là Rails) có thể khiến bạn khó hiểu tại sao có chuyện gì đó xảy ra. Bất kỳ mô-đun nào được khai báo trong đường dẫn tự động tải sẽ chỉ được tải nếu tên mô-đun tương ứng với tên thư mục mẹ. Vì vậy, trong trường hợp bạn cố gắng đưa vào lib/my_stuff/bar.rbmột cái gì đó như:

module Foo
  class Bar
  end
end

Nó sẽ không được tải tự động. Sau đó, một lần nữa nếu bạn đổi tên thư mục mẹ để foolưu trữ mô-đun của bạn tại đường dẫn : lib/foo/bar.rb. Nó sẽ ở đó cho bạn. Một tùy chọn khác là đặt tên cho tệp bạn muốn tự động tải theo tên mô-đun. Rõ ràng chỉ có thể có một tập tin theo tên đó. Trong trường hợp bạn cần chia nội dung của mình thành nhiều tệp, tất nhiên bạn có thể sử dụng một tệp đó để yêu cầu các tệp khác, nhưng tôi không khuyến nghị điều đó, vì khi đó ở chế độ phát triển và bạn sửa đổi các tệp khác đó thì Rails không thể tự động tải lại chúng cho bạn. Nhưng nếu bạn thực sự muốn, bạn có thể có một tệp theo tên mô-đun, sau đó chỉ định các tệp thực tế cần thiết để sử dụng mô-đun. Vì vậy, bạn có thể có hai tệp: lib/my_stuff/bar.rbvà tệp lib/my_stuff/foo.rbtrước giống như trên và tệp sau chứa một dòng duy nhất:require "bar"và điều đó sẽ làm việc như nhau.

PS tôi cảm thấy bắt buộc phải thêm một điều quan trọng. Gần đây, bất cứ khi nào tôi muốn có một cái gì đó trong thư mục lib cần được tải tự động, tôi có xu hướng bắt đầu nghĩ rằng nếu đây là thứ mà tôi thực sự phát triển riêng cho dự án này (thường là vậy, nó có thể là một ngày nào đó biến thành một đoạn mã "tĩnh" được sử dụng trong nhiều dự án hoặc một mô hình con git, v.v. trong trường hợp đó chắc chắn nó phải nằm trong thư mục lib) thì có lẽ vị trí của nó không nằm trong thư mục lib. Có lẽ nó nên ở trong thư mục con trong thư mục ứng dụng · Tôi có cảm giác rằng đây là cách làm việc mới. Rõ ràng, phép thuật tương tự đang hoạt động ở bất cứ nơi nào trong bạn tự động tải các đường dẫn mà bạn đặt công cụ của mình vào để điều đó tốt cho những điều này. Dù sao, đây chỉ là suy nghĩ của tôi về chủ đề này. Bạn được tự do không đồng ý. :)


CẬP NHẬT: Về loại phép thuật ..

Như severin đã chỉ ra trong nhận xét của mình, lõi "tự động tải một cơ chế mô-đun" chắc chắn là một phần của Ruby, nhưng các công cụ đường dẫn tự động tải thì không. Bạn không cần Rails để làmautoload :Foo, File.join(Rails.root, "lib", "my_stuff", "bar"). Và khi bạn cố gắng tham chiếu mô-đun Foo lần đầu tiên thì nó sẽ được tải cho bạn. Tuy nhiên, những gì Rails làm là nó cho chúng ta một cách để thử và tải các thứ tự động từ các thư mục đã đăng ký và điều này đã được thực hiện theo cách mà nó cần phải thừa nhận điều gì đó về các quy ước đặt tên. Nếu nó không được thực hiện như vậy, thì mỗi khi bạn tham chiếu thứ gì đó hiện chưa được tải, nó sẽ phải đi qua tất cả các tệp trong tất cả các thư mục tự động tải và kiểm tra xem có bất kỳ tệp nào trong đó chứa những gì bạn đang cố gắng tham khảo không. Điều này đến lượt nó sẽ đánh bại ý tưởng tự động tải và tự động tải. Tuy nhiên, với các quy ước này, nó có thể khấu trừ từ mô-đun / lớp mà bạn đang cố tải ở nơi có thể được xác định và chỉ tải nó.


1
Tại sao lại là phép thuật Ruby này? Ruby chỉ cung cấp chức năng Module # autoload mà bạn có thể sử dụng để ra lệnh cho tệp đang được tải khi truy cập vào hằng số (không xác định) (xem ruby-doc.org/core-1.9.3/Module.html#method-i-autoload ). Việc kết hợp tên mô-đun / lớp với thư mục / tệp theo ý kiến ​​của tôi được thực hiện trong Rails / ActiveSupport (ví dụ: tại đây: github.com/rails/rails/blob/, ). Liệu tôi có sai?
severin

Vâng, tôi tin rằng bạn là chính xác. Tôi đã quá vội vàng để "sửa" câu trả lời ban đầu của mình khi Zabba chỉ ra "lỗ hổng" của nó. Hãy để tôi cập nhật câu trả lời của tôi thêm một chút để làm rõ vấn đề này.
Timo

1
Tôi đã dành một nửa giờ để mucking về. Tôi cần (muốn) để tự động tải Sprockets :: JSRender :: Bộ xử lý. Có thể tìm thấy đường dẫn bằng cách vào bảng điều khiển rails và thực hiện "Sprockets :: JSRender :: Processor" .underscore và giải thích rằng đó là "sprockets / js numnder / bộ xử lý" (có thêm .rb) HTH.
pedz

Bạn vừa tiết kiệm sự tỉnh táo của tôi. ~ thở dài nhẹ nhõm ~ cảm ơn bạn rất nhiều vì đã chia sẻ :)
Brenden

Cảm ơn bạn cho nhận xét hữu ích nhất này. Tôi không hiểu tại sao một số mô-đun hoạt động như họ đã làm cho đến khi tôi đọc bình luận của bạn. Phước lành cho bạn!
mjnissim

41

Cảnh báo: nếu bạn muốn tải 'bản vá khỉ' hoặc 'lớp mở' từ thư mục 'lib' của mình, đừng sử dụng phương pháp 'tự động tải' !!!

  • " Config.autoload_paths " cách tiếp cận: chỉ hoạt động nếu bạn đang tải một lớp học mà được xác định duy nhất tại một nơi. Nếu một số lớp đã được xác định ở một nơi khác, thì bạn không thể tải lại nó bằng cách tiếp cận này.

  • Cách tiếp cận " config / initizer / load_rb_file.rb ": luôn hoạt động! dù lớp mục tiêu là lớp mới hay "lớp mở" hay "bản vá khỉ" cho lớp hiện có, nó luôn hoạt động!

Để biết thêm chi tiết, xem: https://stackoverflow.com/a/6797707/445908


6
Đây là một sự phân biệt quan trọng để hiểu. Cảm ơn vì điều đó.
Tyler Collier

28

Rất giống nhau, nhưng tôi nghĩ rằng điều này là một chút thanh lịch:

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

18

Trong trường hợp của tôi, tôi đã cố gắng tải một tập tin trực tiếp dưới thư mục lib.

Trong ứng dụng.rb ...

require '/lib/this_file.rb' 

không hoạt động, ngay cả trong bảng điều khiển và sau đó khi tôi đã thử

require './lib/this_file.rb' 

và đường ray tải tập tin hoàn hảo.

Tôi vẫn còn khá và tôi không chắc tại sao nó lại hoạt động nhưng nó hoạt động. Nếu ai đó muốn giải thích cho tôi, tôi sẽ đánh giá cao: DI hy vọng điều này sẽ giúp được ai đó.


2
Đó là bởi vì ./lib/this_file.rb tìm trong thư mục hiện tại (trong bảng điều khiển Rails, đó sẽ là gốc Rails của bạn) và /lib/this_file.rb xem đó là một đường dẫn tuyệt đối. Ví dụ: ./lib/this_file.rb = /var/www/myrailsapp/lib/this_file.rb, /lib/this_file.rb = /lib/this_file.rb
Jason

7

Tôi đã từng gặp vấn đề tương tự. Đây là cách tôi giải quyết nó. Giải pháp tải thư mục lib và tất cả các thư mục con (không chỉ trực tiếp). Tất nhiên bạn có thể sử dụng điều này cho tất cả các thư mục.

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

5
Điều này có tác dụng phụ khó chịu của các quy ước đặt tên Rails hoàn toàn bị che khuất. Nếu lib / bar / foo.rb xác định Bar :: Foo xuất hiện trước lib / foo.rb xác định Foo trong tra cứu tự động tải, thì bạn sẽ gặp các lỗi khó hiểu như Expected lib/bar/foo.rb to define constant Fookhi bạn thử tải lib / foo.rb bằng cách tham khảo Foo không thay đổi.
Jacob

5

config.autoload_paths không hoạt động với tôi. Tôi giải quyết nó theo cách khác

Ruby on rails 3 không tự động tải lại mã (tự động tải) từ thư mục / lib. Tôi giải quyết nó bằng cách đặt vào bên trongApplicationController

Dir["lib/**/*.rb"].each do |path|
  require_dependency path
end 

4

Nếu chỉ một số tệp nhất định cần quyền truy cập vào các mô-đun trong lib, chỉ cần thêm một câu lệnh yêu cầu vào các tệp cần nó. Ví dụ: nếu một mô hình cần truy cập vào một mô-đun, hãy thêm:

require 'mymodule'

ở đầu tập tin model.rb.


50
Bạn không nên sử dụng requiretrong ứng dụng rails, vì nó ngăn ActiveSupport::Dependencies[un] tải mã đó đúng cách. Thay vào đó, bạn nên sử dụng config.autoload_pathsnhư câu trả lời ở trên, sau đó bao gồm / gia hạn theo yêu cầu.
ben_h

13
Cảm ơn bạn @Mike, tôi sẽ làm những gì bạn đã làm, thật tốt khi thấy một lời giải thích tại sao nó xấu, cảm ơn vì đã không xóa câu trả lời.
Pupeno

Điều gì về bao gồm 'mymodule' nếu bạn chỉ muốn tải một mô-đun?
Mike

1
@ben_h Bạn có nên requiretừ bất cứ nơi nào trong ứng dụng Rails không? Trong một nhiệm vụ cào tôi hiện đang require-ing và include-ing một mô-đun sống lib/. Tôi có nên làm điều đó không?
Dennis

@ben_h Tìm kiếm của tôi cho thấy rằng nó phổ biến đối với mã requirecủa bạn lib/(ví dụ: bài đăng trên blog này , câu trả lời SO này ). Tôi vẫn không chắc chắn về tất cả mọi thứ. Bạn có thể đưa ra nhiều bằng chứng đằng sau yêu cầu không sử dụng require?
Dennis

2

Viết đúng tên tệp.

Nghiêm túc. Tôi đã chiến đấu với một lớp trong một giờ vì lớp đó là Governance :: ArchitectureBoard và tệp nằm ở lib / quản trị / architecture_baord.rb (chuyển O và A trong "bảng")

Có vẻ rõ ràng khi nhìn lại, nhưng đó là ma quỷ theo dõi xuống. Nếu lớp không được định nghĩa trong tệp mà Rails mong đợi nó sẽ dựa trên việc trộn tên lớp, thì đơn giản là nó sẽ không tìm thấy nó.


2

Tính đến Rails 5, nó được khuyến khích để đưa vào thư mục lib dưới thư mục ứng dụng hoặc thay vì tạo ra các không gian tên có ý nghĩa khác cho thư mục như services, presenters, featuresvv và đặt nó dưới thư mục ứng dụng để tự động tải bằng đường ray.

Vui lòng kiểm tra Liên kết thảo luận GitHub này .


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.