Rails 5: Tải các tập tin lib trong sản xuất


128

Tôi đã nâng cấp một trong những ứng dụng của mình từ Rails 4.2.6 lên Rails 5.0.0. Các Hướng dẫn nâng cấp nói rằng tính năng Autoload hiện đang bị vô hiệu hóa trong sản xuất theo mặc định.

Bây giờ tôi luôn gặp lỗi trên máy chủ sản xuất của mình vì tôi tải tất cả các tệp lib có tự động tải trong application.rbtệp.

module MyApp
    class Application < Rails::Application
        config.autoload_paths += %W( lib/ )
    end
end

Còn bây giờ, tôi đã thiết lập config.enable_dependency_loadingđể truenhưng tôi tự hỏi, nếu có một giải pháp tốt hơn cho việc này. Phải có một lý do mà Tự động tải bị tắt trong sản xuất theo mặc định.


điều điên rồ, và tài liệu vẫn bảo bạn làm auto_load. Tôi đã rất bối rối những gì đang xảy ra trong sản xuất env cho một ứng dụng mới. Và kể từ khi tôi bắt đầu học với Rails 5, tôi đã không đọc hướng dẫn di chuyển. Tôi đã gửi một vấn đề tài liệu để hy vọng giải quyết vấn đề này: github.com/rails/rails/issues/27268
akostadinov

1
thật ngạc nhiên, tôi có hai tệp trong libthư mục, một tệp có sẵn dễ dàng trong Thời gian chạy, nhưng một tệp khác phải được yêu cầu thủ công: D
ảo ảnh

@Tobias Bạn đã kết thúc giải pháp nào?
Geoboy

@geoboy Tôi nhóm mã (như Validators) trong các thư mục trực tiếp trong ứng dụng / thư mục vì mã được tải tự động.
Tobias

Đây là về đường dẫn tệp thích hợp và định nghĩa lớp ở đây là những gì phù hợp với tôi trong Rails 5.2: Đường dẫn tệp: app/services/paylinx/paylinx_service.rbĐịnh nghĩa lớp : module Paylinx class PaylinxService end end. Tôi đã thử những autoload_pathsthứ này . không làm việc cho tôi.
Nam

Câu trả lời:


161

Danh sách các thay đổi của tôi sau khi chuyển sang Rails 5:

  1. Đặt libdir vào appvì tất cả mã bên trong ứng dụng được tự động tải trong dev và háo hức được tải trong prod và quan trọng nhất là được tải tự động trong quá trình phát triển để bạn không phải khởi động lại máy chủ mỗi khi bạn thực hiện thay đổi.
  2. Xóa mọi requirecâu lệnh trỏ đến các lớp của riêng bạn bên trong libbởi vì tất cả chúng đều được tự động tải nếu cách đặt tên tệp / thư mục của chúng là chính xác và nếu bạn để lại các requirecâu lệnh thì nó có thể phá vỡ tự động tải. Thêm thông tin ở đây
  3. Đặt config.eager_load = truetrong tất cả các môi trường để xem các vấn đề tải mã háo hức trong dev.
  4. Sử dụng Rails.application.eager_load!trước khi chơi với các chủ đề để tránh các lỗi "phụ thuộc vòng tròn".
  5. Nếu bạn có bất kỳ tiện ích mở rộng ruby ​​/ rails nào thì hãy để mã đó trong libthư mục cũ và tải chúng theo cách thủ công từ trình khởi tạo. Điều này sẽ đảm bảo rằng các tiện ích mở rộng được tải trước logic tiếp theo của bạn có thể phụ thuộc vào nó:

    # config/initializers/extensions.rb
    Dir["#{Rails.root}/lib/ruby_ext/*.rb"].each { |file| require file }
    Dir["#{Rails.root}/lib/rails_ext/*.rb"].each { |file| require file }

8
Vậy làm thế nào để một người sử dụng libthư mục bây giờ? Tôi có nghĩa là di chuyển libdir vào appdir có vẻ giống như một cách giải quyết.
Martin Svoboda

3
/app/lib/đã đặt một tập tin / lớp và nó KHÔNG tự động tải. thử nghiệm trên đường ray 5.1, dự án mới
Tim Kretschmer

29
Điều đáng chú ý là bạn cần dừng mùa xuân. Tôi đã chuyển mọi thứ sang app / lib / và sau đó lãng phí một chút thời gian để tự hỏi tại sao tôi vẫn không thể sử dụng các lớp học của mình từ bảng điều khiển. dừng mùa xuân ftw :)
jacklin

1
Dòng sau sẽ đi về đâuRails.application.eager_load!
Steven Aguilar

1
Điều này có thể làm việc nhưng nó không phải là giải pháp tốt nhất. Cấu trúc thư mục là ngữ nghĩa là tốt. Những thứ trong libcó một sự gần gũi nhận thức khác nhau đối với dự án so với những thứ trong appthư mục. Một số câu trả lời khác tốt hơn câu trả lời này.
CWitty

84

Tôi chỉ sử dụng config.eager_load_pathsthay vì config.autoload_pathsthích đề cập đến akostadinov trên bình luận của github: https://github.com/rails/rails/issues/13142#issuecomment-275492070

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

Nó hoạt động trên môi trường phát triển và sản xuất.

Cảm ơn Johan đã đề nghị thay thế #{Rails.root}/libbằng Rails.root.join('lib')!


3
Hoạt động như một lá bùa. Tôi không thích cú pháp nên đã đổi nó thành config.eager_load_paths << Rails.root.join('lib').
3limin4t0r

2
Đối với tôi đó là câu trả lời tốt nhất. Dự án của tôi bắt đầu trên Rails 5.2 từ đầu và thư mục / lib vẫn được tạo bên ngoài thư mục / app. Tôi đã không thấy một lý do tốt để di chuyển nó.
Samir Haddad

1
Đúng, điều này hoạt động! Có vẻ như các nhà phát triển Rails thực sự thích gây ra vấn đề tải lib: D cho đến lần tiếp theo!
Damien Roche

To Rails 5.2 sử dụng config.eager_load_paths += [Rails.root.join('lib')]thay vì vì config.eager_load_pathsmột mảng bị đóng băng
William Wong Garay

@WilliamWongGaray config.eager_load_paths chỉ đọc khi bạn cố gắng sửa đổi nó trong trình khởi tạo. Khi bạn thêm đường dẫn trong application.rbnó sẽ hoạt động bằng cả hai phương thức.
Michał Zalewski

31

Tự động tải bị vô hiệu hóa trong môi trường sản xuất vì an toàn luồng. Cảm ơn bạn @ ёелёный cho liên kết.

Tôi đã giải quyết vấn đề này bằng cách lưu trữ các tệp lib trong một libthư mục trong thư mục của tôi appnhư được đề xuất trên Github . Mỗi thư mục trong appthư mục được tải bởi Rails tự động.


6
Nếu bạn không muốn tìm hiểu về chủ đề thảo luận dài trên Github, bạn có thể tìm thấy lời giải thích được chắt lọc tại đây: collectiveidea.com/blog/archives/2016/07/22/ trên
Ernest

7
Tôi đã sử dụng config.eager_load_paths << "#{Rails.root}/lib", đó là IMO tốt hơn để theo cấu trúc ứng dụng đường ray được đề xuất.
akostadinov

2
Việc đưa lib vào app/libđược khuyến nghị bởi các thành viên rails github.com/rails/rails/issues/13142#issuecomment-275549669
eXa

4
Điều này hoàn toàn làm hỏng mục đích của libnó là gì. Tôi sẽ chờ cho gentlove hoặc DHH hòa nhập. Trong lúc này, tôi (cá nhân) khuyên bạn nên gắn bó với câu trả lời của @Lev Lukomsky.
Josh Brody

@JoshBrody Ý kiến ​​của tôi bây giờ là bạn không cần /libthư mục nào cả. Libs bên thứ ba là hầu hết các đá quý thời gian và nếu không nên có một viên đá quý được tạo ra. Đối với các tệp khác, tôi tạo các thư mục cụ thể trong thư mục /app. Ví dụ validators.
Tobias

22

Phải có một lý do mà Tự động tải bị tắt trong sản xuất theo mặc định.

Đây là một cuộc thảo luận dài về vấn đề này. https://github.com/rails/rails/issues/13142


1
Cuộc thảo luận này là tốt nhất, mặc dù là một nguồn thông tin dài đọc, về chủ đề mà tôi đã đi qua.
Jason

12

Điều này cho phép tải lib tự động và cũng hoạt động trong môi trường sản xuất.

PS Tôi đã thay đổi câu trả lời của mình, bây giờ nó thêm vào cả hai đường dẫn tự động tải, bất kể môi trường, để cho phép làm việc trong môi trường tùy chỉnh quá (như giai đoạn)

# config/initializers/load_lib.rb
...
config.eager_load_paths << Rails.root.join('lib')
config.autoload_paths << Rails.root.join('lib')
...

2
Bạn có thể mở rộng lý do tại sao điều này khắc phục vấn đề?
Stuart.Sklinar

@ Stuart.Sklinar điều này cho phép tải lib tự động và cũng hoạt động trong môi trường sản xuất. PS Tôi đã thay đổi câu trả lời của tôi, bây giờ nó làm tăng thêm cả một con đường autoload eager-, bất kể môi trường, cho phép làm việc trong môi trường tùy chỉnh quá (như giai đoạn)
srghma

1
Bạn có thể mở rộng (Trong câu trả lời của bạn)? Mã chỉ trả lời không thực sự giúp bất cứ ai hiểu tại sao nên thực hiện "theo cách đó" - Tôi nên thêm Tôi không phải là nhà phát triển Ruby, chỉ giúp làm sáng tỏ SO. Thêm một số bình luận vào một "câu trả lời chỉ mã" sẽ cung cấp cho nó một số bối cảnh thực tế.
Stuart.Sklinar

1
@ Stuart.Sklinar chắc chắn
srghma

6

Chỉ cần thay đổi config.autoload_paths thành config.eager_load_paths trong tệp config / application.rb. Bởi vì trong rails 5 tự động tải bị tắt cho môi trường sản xuất theo mặc định. Để biết thêm chi tiết xin vui lòng theo liên kết .

 #config.autoload_paths << "#{Rails.root}/lib"
  config.eager_load_paths << Rails.root.join('lib')

Nó hoạt động cho cả phát triển môi trường và sản xuất.


4

Theo một cách hiểu nào đó, đây là một cách tiếp cận thống nhất trong Rails 5 để tập trung cấu hình háo hức và tự động tải, đồng thời nó thêm đường dẫn tự động tải yêu cầu bất cứ khi nào tải háo hức được cấu hình nếu không nó sẽ không thể hoạt động chính xác:

# config/application.rb
...
config.paths.add Rails.root.join('lib').to_s, eager_load: true

# as an example of autoload only config
config.paths.add Rails.root.join('domainpack').to_s, autoload: true
...


0

Chuyển thư mục lib sang ứng dụng đã giúp giải quyết vấn đề, api Twitter của tôi sẽ không chạy trong sản xuất. Tôi đã có "TwitterApi hằng số chưa được khởi tạo" và API Twitter của tôi nằm trong thư mục lib của tôi. Tôi đã cóconfig.autoload_paths += Dir["#{Rails.root}/app/lib"] trong application.rb của mình nhưng nó không hoạt động trước khi di chuyển thư mục.

Điều này đã lừa


-6

để tóm tắt câu trả lời của Lev: mv lib appđã đủ để có tất cả của tôilib mã tự động tải / tự động tải lại.

(rails 6.0.0beta3 nhưng cũng hoạt động tốt trên rails 5.x)

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.