Rails 5: Memuat file lib dalam produksi

128

Saya telah memperbarui salah satu aplikasi saya dari Rails 4.2.6 ke Rails 5.0.0. The Peningkatan Panduan mengatakan, bahwa fitur autoload sekarang dinonaktifkan dalam produksi secara default.

Sekarang saya selalu mendapatkan kesalahan pada server produksi saya karena saya memuat semua file lib dengan autoload dalam application.rbfile.

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

Untuk saat ini, saya telah mengatur config.enable_dependency_loadinguntuk truetetapi saya ingin tahu apakah ada solusi yang lebih baik untuk ini. Pasti ada alasan bahwa Autoloading dinonaktifkan dalam produksi secara default.

Tobias
sumber
hal yang gila, dan dokumen masih memberitahu Anda untuk melakukan auto_load. Saya sangat bingung apa yang salah dalam produksi untuk aplikasi baru. Dan sejak saya mulai belajar dengan Rails 5 saya tidak membaca panduan migrasi. Saya mengajukan masalah dokumen agar mudah-mudahan diselesaikan: github.com/rails/rails/issues/27268
akostadinov
1
luar biasa, saya memiliki dua file dalam libdir, satu file mudah tersedia di Runtime, tetapi yang lain harus diperlukan secara manual: D
ilusionis
@Tobias Solusi apa yang akhirnya Anda dapatkan?
geoboy
@geoboy I mengelompokkan kode (seperti Validators) di folder langsung di app / direktori karena kode ada yang dimuat secara otomatis.
Tobias
ini tentang path file yang tepat dan definisi kelas di sini adalah apa yang bekerja untuk saya di Rails 5.2: Berkas path: app/services/paylinx/paylinx_service.rbdefinisi Kelas: module Paylinx class PaylinxService end end. Saya mencoba autoload_pathshal - hal ini . tidak bekerja untuk saya.
NamNamNam

Jawaban:

161

Daftar perubahan saya setelah pindah ke Rails 5:

  1. Tempat lib dir ke appkarena semua kode di dalam aplikasi dimuat secara otomatis di dev dan bersemangat dimuat di prod dan yang paling penting adalah memuat otomatis dalam pengembangan sehingga Anda tidak perlu me-restart server setiap kali Anda membuat perubahan.
  2. Hapus requirepernyataan yang menunjuk ke kelas Anda sendiri di dalam libkarena mereka semua tetap dimuat secara otomatis jika penamaan file / dir mereka benar, dan jika Anda meninggalkan requirepernyataan itu dapat merusak autoreloading. Info lebih lanjut di sini
  3. Atur config.eager_load = truedi semua lingkungan untuk melihat masalah pemuatan kode dengan penuh semangat di dev.
  4. Gunakan Rails.application.eager_load!sebelum bermain dengan utas untuk menghindari kesalahan "ketergantungan sirkular".
  5. Jika Anda memiliki ekstensi ruby ​​/ rails maka biarkan kode itu di dalam libdirektori lama dan muat secara manual dari initializer. Ini akan memastikan bahwa ekstensi dimuat sebelum logika Anda selanjutnya yang dapat bergantung padanya:

    # 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 }
Lev Lukomsky
sumber
8
Jadi bagaimana cara menggunakan libfolder sekarang? Maksud saya pindah libdir ke appdir sepertinya semacam solusi.
Martin Svoboda
3
/app/lib/menempatkan file / kelas dan itu TIDAK autoloading. diuji di rel 5.1, proyek baru
Tim Kretschmer
29
Perlu dicatat bahwa Anda perlu menghentikan musim semi. Saya memindahkan semuanya ke app / lib / dan kemudian membuang-buang waktu bertanya-tanya mengapa saya masih tidak bisa menggunakan kelas saya dari konsol. spring stop ftw :)
jacklin
1
Ke mana baris berikut akan ditujuRails.application.eager_load!
Steven Aguilar
1
Ini mungkin berhasil tetapi itu bukan solusi terbaik. Struktur folder juga semantik. Hal-hal di libmemiliki kedekatan yang dirasakan berbeda dengan proyek dari hal-hal dalam appdirektori. Beberapa jawaban lain lebih baik daripada yang ini.
CWitty
84

Saya hanya menggunakan config.eager_load_pathsalih-alih config.autoload_pathsseperti menyebutkan akostadinov di github komentar: https://github.com/rails/rails/issues/13142#issuecomment-275492070

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

Ini bekerja pada pengembangan dan lingkungan produksi.

Terima kasih Johan untuk saran untuk mengganti #{Rails.root}/libdengan Rails.root.join('lib')!

Michał Zalewski
sumber
3
Bekerja seperti pesona. Saya tidak suka sintaksnya sehingga mengubahnya menjadi config.eager_load_paths << Rails.root.join('lib').
3limin4t0r
2
Bagi saya itu adalah jawaban terbaik. Proyek saya dimulai pada Rails 5.2 dari awal dan folder / lib masih dibuat di luar folder / app. Saya tidak melihat alasan yang baik untuk memindahkannya.
Samir Haddad
1
Yap, ini berhasil! Sepertinya Rails devs benar-benar menikmati menyebabkan masalah pemuatan lib: D hingga waktu berikutnya!
Damien Roche
Untuk Rails 5.2 menggunakan config.eager_load_paths += [Rails.root.join('lib')]karena config.eager_load_pathsarray beku
William Wong Garay
@WilliamWongGaray config.eager_load_paths hanya-baca ketika Anda mencoba memodifikasinya di penginisialisasi. Ketika Anda menambahkan jalur di application.rbdalamnya akan bekerja menggunakan kedua metode.
Michał Zalewski
31

Autoloading dinonaktifkan di lingkungan produksi karena keselamatan ulir. Terima kasih kepada @ Зелёный untuk tautannya.

Saya memecahkan masalah ini dengan menyimpan file lib di libfolder di appdirektori saya seperti yang direkomendasikan di Github . Setiap folder dalam appfolder akan dimuat oleh Rails secara otomatis.

Tobias
sumber
6
Jika Anda tidak ingin menggali utas diskusi panjang tentang Github, Anda dapat menemukan penjelasan yang disaring di sini: kolektifidea.com/blog/archives/2016/07/22/…
Ernest
7
Saya menggunakan config.eager_load_paths << "#{Rails.root}/lib", itu IMO yang lebih baik untuk mengikuti struktur aplikasi rel yang direkomendasikan.
akostadinov
2
Memasukkan lib ke dalam app/libdirekomendasikan oleh anggota rel github.com/rails/rails/issues/13142#issuecomment-275549669
eXa
4
Ini benar-benar menghancurkan apa tujuannya lib. Saya akan menunggu tenderlove atau DHH untuk berpadu. Sementara itu, saya (secara pribadi) akan merekomendasikan tetap dengan jawaban @Lev Lukomsky.
Josh Brody
@ JoshBrody Pendapat saya sekarang adalah bahwa Anda tidak perlu /libdirektori sama sekali. Lib pihak ketiga adalah sebagian besar permata waktu dan jika tidak harus ada permata yang dibuat. Untuk file lain, saya membuat folder spesifik di /appdirektori. Sebagai contoh validators.
Tobias
22

Pasti ada alasan bahwa Autoloading dinonaktifkan dalam produksi secara default.

Berikut ini diskusi panjang tentang masalah ini. https://github.com/rails/rails/issues/13142

Зелёный
sumber
1
Diskusi ini adalah sumber informasi terbaik, walaupun sudah lama dibaca, tentang subjek yang saya temui.
Jason
12

Ini memungkinkan untuk memuat otomatis lib, dan bekerja di lingkungan produksi juga.

NB Saya telah mengubah jawaban saya, sekarang ini menambah kedua jalur pengisian otomatis, terlepas dari lingkungan, untuk memungkinkan pekerjaan di lingkungan kustom juga (seperti panggung)

# config/initializers/load_lib.rb
...
config.eager_load_paths << Rails.root.join('lib')
config.autoload_paths << Rails.root.join('lib')
...
srghma
sumber
2
Bisakah Anda memperluas mengapa ini memperbaiki masalah?
Stuart.Sklinar
@ Stuart.Sklinar ini memungkinkan untuk memiliki lib autoreload, dan bekerja di lingkungan produksi juga. PS Saya telah mengubah jawaban saya, sekarang ini menambah kedua jalur pengisian otomatis, terlepas dari lingkungan, untuk memungkinkan pekerjaan di lingkungan kustom juga (seperti panggung)
srghma
1
Bisakah Anda memperluas (Dalam jawaban Anda)? Kode hanya menjawab tidak benar-benar membantu orang memahami mengapa itu harus dilakukan "seperti itu" - Saya harus menambahkan saya bukan seorang dev Ruby, hanya membantu membersihkan SO. Menambahkan beberapa komentar ke "jawaban kode saja" akan memberinya konteks aktual.
Stuart. Sklinar
1
@ Stuart.Sklinar yakin
srghma
6

Ubah saja config.autoload_paths ke config.eager_load_paths dalam file config / application.rb. Karena pada rel 5 autoloading dinonaktifkan untuk lingkungan produksi secara default. Untuk lebih jelasnya silakan ikuti tautan .

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

Ini berfungsi baik untuk pengembangan lingkungan dan produksi.

Jitendra Rathor
sumber
4

Dalam beberapa hal, berikut ini adalah pendekatan terpadu dalam Rails 5 untuk memusatkan konfigurasi eager dan autoload, sekaligus menambah jalur autoload yang diperlukan setiap kali eager load dikonfigurasi jika tidak maka tidak akan dapat bekerja dengan benar:

# 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
...
pocheptsov
sumber
2

Bagi siapa pun yang berjuang dengan ini seperti saya, tidak cukup hanya dengan menempatkan direktori di bawah app/. Ya, Anda akan mendapatkan autoloading tetapi tidak perlu memuat ulang, yang mengharuskan konvensi penempatan nama harus dipenuhi .

Juga, menggunakan penginisialisasi untuk memuat level root yang lama libakan mencegah fitur reload selama pengembangan.

Abdullah Barrak
sumber
0

Memindahkan folder lib ke aplikasi membantu menyelesaikan masalah, api Twitter saya tidak akan berjalan dalam produksi. Saya memiliki "TwitterApi konstan tidak diinisialisasi" dan API Twitter saya ada di folder lib saya. Saya punyaconfig.autoload_paths += Dir["#{Rails.root}/app/lib"] di application.rb saya tetapi tidak berhasil sebelum memindahkan folder.

Ini berhasil

Laurie
sumber
-6

untuk meringkas jawaban Lev: mv lib appsudah cukup untuk memiliki semua milikkulib kode autoloaded / auto-reloaded.

(rel 6.0.0beta3 tetapi harus bekerja dengan baik pada rel 5.x juga)

localhostdotdev
sumber