Rails 3.1: Engine เทียบกับแอพที่ติดตั้งได้


120

ใครช่วยให้ฉันเข้าใจความแตกต่างระหว่าง Rails Engine กับแอพ Mountable ได้ไหม ใน Rails 3.1 คุณสามารถสร้างได้โดยใช้คำสั่ง"rail new plugin _ __ "

rails plugin new forum --full        # Engine
rails plugin new forum --mountable   # Mountable App

คุณต้องการใช้เมื่อใด ฉันรู้ว่าคุณสามารถบรรจุเครื่องยนต์เป็นอัญมณีได้ นั่นไม่ใช่กรณีของแอพที่ติดตั้งได้หรือไม่? มีความแตกต่างอะไรอีกบ้าง?

คำตอบ:


143

ฉันสังเกตเห็นสิ่งต่อไปนี้:

เครื่องยนต์เต็มรูปแบบ

ด้วยเครื่องยนต์เต็มรูปแบบแอปพลิเคชันแม่จะสืบทอดเส้นทางจากเครื่องยนต์ ไม่จำเป็นต้องระบุอะไรในparent_app/config/routes.rb. การระบุอัญมณีใน Gemfile เพียงพอสำหรับแอปพาเรนต์ในการสืบทอดโมเดลเส้นทางและอื่น ๆ เส้นทางเครื่องยนต์ถูกระบุเป็น:

# my_engine/config/routes.rb 
Rails.application.routes.draw do 
  # whatever 
end 

ไม่มีการกำหนดเนมสเปซของโมเดลคอนโทรลเลอร์และอื่น ๆ สิ่งเหล่านี้สามารถเข้าถึงได้ทันทีในแอปพลิเคชันหลัก

เครื่องยนต์ที่ติดตั้งได้

เนมสเปซของเครื่องยนต์ถูกแยกโดยค่าเริ่มต้น:

# my_engine/lib/my_engine/engine.rb
module MyEngine 
  class Engine < Rails::Engine 
    isolate_namespace MyEngine 
  end 
end

ด้วยเอ็นจิ้นที่ติดตั้งได้เส้นทางจะถูกเนมสเปซและแอพพาเรนต์สามารถรวมฟังก์ชันนี้ไว้ในเส้นทางเดียว:

# my_engine/config/routes.rb 
MyEngine::Engine.routes.draw do 
  #whatever 
end 

# parent_app/config/routes.rb 
ParentApp::Application.routes.draw do 
    mount MyEngine::Engine => "/engine", :as => "namespaced" 
end 

โมเดลคอนโทรลเลอร์และอื่น ๆ จะแยกออกจากแอปพลิเคชันหลัก - แม้ว่าตัวช่วยจะสามารถแชร์ได้อย่างง่ายดาย

นี่คือความแตกต่างหลักที่ฉันเห็น บางทีอาจมีคนอื่น? ฉันได้ถามมากกว่าที่นี่แต่ยังไม่ได้รับการตอบสนอง

ความประทับใจของฉันคือเนื่องจากเอนจินเต็มรูปแบบไม่ได้แยกตัวเองออกจากแอปพลิเคชันหลักจึงควรใช้เป็นแอปพลิเคชันแบบสแตนด์อโลนที่อยู่ติดกับแอปหลัก ฉันเชื่อว่าการปะทะกันของชื่ออาจเกิดขึ้นได้

สามารถใช้เครื่องยนต์ที่ติดตั้งได้ในสถานการณ์ที่คุณต้องการหลีกเลี่ยงความขัดแย้งของชื่อและรวมเครื่องยนต์ไว้ภายใต้เส้นทางเดียวในแอปพลิเคชันหลัก ตัวอย่างเช่นฉันกำลังสร้างเครื่องยนต์ตัวแรกที่ออกแบบมาเพื่อการบริการลูกค้า แอปพลิเคชันหลักสามารถรวมฟังก์ชันการทำงานไว้ภายใต้เส้นทางเดียวเช่น:

mount Cornerstone::Engine => "/cornerstone", :as => "help" 

หากฉันไม่เข้าใจสมมติฐานใครบางคนโปรดแจ้งให้เราทราบแล้วฉันจะแก้ไขคำตอบนี้ ฉันได้ทำบทความเล็ก ๆ เกี่ยวกับเรื่องนี้ที่นี่ ไชโย!


1
เครื่องยนต์ที่ติดตั้งได้สามารถกำหนดเส้นทาง / ติดตั้งที่รูทของแอปแม่ได้หรือไม่?
Slick23

3
@JustinM ลองดูmount MyEngine::Engine => "/"สิ มันใช้งานได้กับทรัพยากรบางทีนั่นอาจเป็นกรณีของเครื่องยนต์ด้วย
Benoit Garret

2
@astjohn บทสรุปที่ยอดเยี่ยมของบล็อกของคุณ แต่มันจะไม่เป็นแบบอื่นเหรอ? Full Engine จะ "ไม่สมบูรณ์" และต้องใช้แอปหลักในการทำงานในขณะที่ Mountable Engine สามารถทำงานแบบสแตนด์อะโลนได้เนื่องจาก "แยก" จากแอปหลัก
Theo Scholiadis

39

ตัวเลือกทั้งสองจะสร้างเครื่องมือ ความแตกต่างคือ--mountableจะสร้างเอ็นจิ้นในเนมสเปซที่แยกได้ในขณะที่--fullจะสร้างเอ็นจิ้นที่แชร์เนมสเปซของแอพหลัก

ความแตกต่างจะปรากฏใน 3 วิธี:

1) ไฟล์คลาสเครื่องยนต์จะเรียกisolate_namespace:

lib / my_full_engine / engine.rb:

module MyFullEngine
  class Engine < Rails::Engine
  end
end

lib / my_mountable_engine / engine.rb:

module MyMountableEngine
  class Engine < Rails::Engine
    isolate_namespace MyMountableEngine # --mountable option inserted this line
  end
end

2) config/routes.rbไฟล์ของเครื่องยนต์จะถูกเนมสเปซ:

เครื่องยนต์เต็มรูปแบบ:

Rails.application.routes.draw do
end

เครื่องยนต์ที่ติดตั้ง:

MyMountableEngine::Engine.routes.draw do
end

3) โครงสร้างไฟล์สำหรับตัวควบคุมผู้ช่วยเหลือมุมมองและเนื้อหาจะเป็นเนมสเปซ:

สร้างแอป / คอนโทรลเลอร์ / my_mountable_engine /application_controller.rb
สร้างแอพ / ตัวช่วย / my_mountable_engine /application_helper.rb
สร้างแอพ / เมลสร้างแอพ / โมเดล
สร้างแอพ / มุมมอง / เลย์เอาต์ / my_mountable_engine /application.html.erb
สร้างแอพ / สินทรัพย์ / รูปภาพ / my_mountable_engine
สร้าง app / assets / stylesheets / my_mountable_engine /application.css
สร้าง app / assets / javascripts / my_mountable_engine /application.js
สร้าง config / route.rb สร้าง lib / my_mountable_engine.rb
สร้าง lib / งาน / my_mountable_engine.rake
สร้าง lib / my_mountable_ version .rb
สร้าง lib / my_mountable_engine / engine.rb


คำอธิบาย

กรณีการใช้งานสำหรับ--fullตัวเลือกดูเหมือนจะ จำกัด มาก โดยส่วนตัวแล้วฉันไม่สามารถคิดถึงเหตุผลที่ดีได้ว่าทำไมคุณถึงต้องการแยกโค้ดของคุณออกเป็นเอนจิ้นโดยไม่แยกเนมสเปซออกไปด้วย - โดยพื้นฐานแล้วมันจะให้แอพพลิเคชั่นสองตัวที่ทำงานร่วมกันอย่างแน่นหนาซึ่งแชร์โครงสร้างไฟล์ที่เหมือนกันและความขัดแย้งและการรั่วไหลของโค้ดทั้งหมด ที่เกี่ยวข้อง

ชิ้นส่วนของเอกสารทุกคนที่ผมเคยเห็นแสดงให้เห็นถึง--mountableตัวเลือกและแน่นอนปัจจุบันคู่มือขอบขอสนับสนุนให้คุณสามารถรวมisolate namespace- ซึ่งเป็นเช่นเดียวกับการพูดว่าการใช้งานมากกว่า--mountable--full

ในที่สุดก็มีความสับสนของคำศัพท์: น่าเสียดายที่rails plugin -hแสดงคำอธิบายต่อไปนี้:

[--full] # สร้างเครื่องยนต์รางพร้อมแอปพลิเคชั่น Rails ที่รวมไว้สำหรับการทดสอบ
[- สามารถติดตั้งได้] # สร้างแอปพลิเคชั่นแยกที่ติดตั้งได้

สิ่งนี้ให้ความรู้สึกว่าคุณใช้--fullสร้าง--mountable"เอนจิ้น" และสร้างสิ่งอื่นที่เรียกว่า "แอปพลิเคชันที่ติดตั้งได้" ซึ่งในความเป็นจริงมันเป็นทั้งเครื่องยนต์ - หนึ่งชื่อและไม่มี ซึ่งจะนำไปสู่ความสับสนเนื่องจากผู้ใช้ที่ต้องการสร้างเอ็นจิ้นจะถือว่า--fullเป็นตัวเลือกที่เกี่ยวข้องมากกว่า

ข้อสรุป

  • rails plugin new something --full= Engine ในเนมสเปซของแอปของคุณ (คุณจะทำไม?)
  • rails plugin new something --mountable= เครื่องยนต์ที่มีเนมสเปซของตัวเอง (น่ากลัว)

อ้างอิง


9
มีเหตุผลที่ดีอย่างหนึ่งที่ควรใช้--full: หากคุณมีบางส่วนของเว็บไซต์ทางรถไฟที่คุณต้องการรวมไว้ (ไม่ใช่ในเนมสเปซแยก) และยังคงแบ่งปันระหว่างโครงการรางต่างๆ นอกจากนี้อาจจะง่ายกว่านั้น: บางทีอัญมณีของคุณอาจไม่ได้เพิ่มมากขนาดนั้น แต่คุณต้องการให้สามารถเชื่อมต่อได้อย่างถูกต้อง
nathanvda

2
@nathanvda - ถูกต้อง แต่ฉันคิดว่าถ้าคุณกำลังแชร์อะไรบางอย่างกับหลาย ๆ โปรเจ็กต์มันควรจะเป็นเนมสเปซเพราะโดยพื้นฐานแล้วคุณใช้มันเป็นปลั๊กอิน
Yarin

ฉันคิดว่าคุณอาจต้องการใช้ - เต็มถ้าคุณต้องการแยกไฟล์ของคุณเนมสเปซไซต์การโทรของคุณเมื่อคุณทำAdmin::AdminService.some_actionแต่ไม่ต้องเปลี่ยนเส้นทางของคุณหากแอปพลิเคชันฝั่งไคลเอ็นต์อื่น ๆ เช่นแอป Ember ใช้เส้นทางที่เกี่ยวข้องกับรหัสของคุณ ต้องการแยก - ดูเหมือนว่าจะเป็นขั้นตอนกลางที่อาจใช้งานได้ง่ายกว่า
Jwan622

ขณะนี้ฉันกำลังดำเนินการเกี่ยวกับแอปพลิเคชันระหว่างประเทศที่ต้องจัดการกับกฎระเบียบเฉพาะประเทศ แต่ยังเปิดเผยอินเทอร์เฟซเดียวกันให้กับทั่วโลก ฉันมี "Core" หนึ่งอินสแตนซ์ต่อประเทศไม่จำเป็นต้องจัดการทั้งหมดพร้อมกัน "กลไกของประเทศ" ไม่สมเหตุสมผลในตัวมันเองดังนั้นการเชื่อมต่อกับแอป "หลัก" จึงไม่ใช่ปัญหา อย่างไรก็ตามฉันไม่ต้องการให้พวกเขาอยู่ในเนมสเปซของตัวเองเพราะแอปหลักต้องไม่ทราบว่าดำเนินการในประเทศใด ฉันรู้สึกว่าเอ็นจิ้นที่ "เต็ม" นั้นเหมือนกับการจัดระเบียบไฟล์และชั้นเรียนของคุณด้วยวิธีแยกส่วน แต่ยังคงรักษา "เสาหิน" ของคุณเอาไว้
Mankalas

17

ฉันก็สงสัยเหมือนกันและด้วยเหตุนี้จึงลงเอยที่นี่ สำหรับฉันแล้วดูเหมือนว่าคำตอบก่อนหน้านี้จะครอบคลุมคำถาม แต่ฉันคิดว่าสิ่งต่อไปนี้อาจช่วยได้เช่นกัน:

# generate plugins (NOTE: using same name each time to minimize differences)
# -----------------------------------------------------------------------------

$ rails plugin new test-plugin -T
$ mv test-plugin{,.01}

$ rails plugin new test-plugin -T --mountable
$ mv test-plugin{,.02}

$ rails plugin new test-plugin -T --full
$ mv test-plugin{,.03}

$ rails plugin new test-plugin -T --full --mountable
$ mv test-plugin{,.04}




# compare "stock" (01) with "mountable" (02)
# -----------------------------------------------------------------------------

$ diff -r test-plugin.01 test-plugin.02

Only in test-plugin.02: app
Only in test-plugin.02: config
Only in test-plugin.02/lib/test-plugin: engine.rb
diff -r test-plugin.01/lib/test-plugin.rb test-plugin.02/lib/test-plugin.rb
0a1,2
> require "test-plugin/engine"
> 
Only in test-plugin.02: script
diff -r test-plugin.01/test-plugin.gemspec test-plugin.02/test-plugin.gemspec
18a19
>   # s.add_dependency "jquery-rails"




# compare "stock" (01) with "full" (03)
# -----------------------------------------------------------------------------

$ diff -r test-plugin.01 test-plugin.03
Only in test-plugin.03: app
Only in test-plugin.03: config
Only in test-plugin.03/lib/test-plugin: engine.rb
diff -r test-plugin.01/lib/test-plugin.rb test-plugin.03/lib/test-plugin.rb
0a1,2
> require "test-plugin/engine"
> 
Only in test-plugin.03: script
diff -r test-plugin.01/test-plugin.gemspec test-plugin.03/test-plugin.gemspec
18a19
>   # s.add_dependency "jquery-rails"




# compare "mountable" (02) with "full" (03)
# -----------------------------------------------------------------------------

$ diff -r test-plugin.02 test-plugin.03

Only in test-plugin.03/app/assets/javascripts/test-plugin: .gitkeep
Only in test-plugin.02/app/assets/javascripts/test-plugin: application.js
Only in test-plugin.03/app/assets/stylesheets/test-plugin: .gitkeep
Only in test-plugin.02/app/assets/stylesheets/test-plugin: application.css
Only in test-plugin.03/app/controllers: .gitkeep
Only in test-plugin.02/app/controllers: test-plugin
Only in test-plugin.03/app/helpers: .gitkeep
Only in test-plugin.02/app/helpers: test-plugin
Only in test-plugin.03/app/mailers: .gitkeep
Only in test-plugin.03/app/models: .gitkeep
Only in test-plugin.03/app/views: .gitkeep
Only in test-plugin.02/app/views: layouts
diff -r test-plugin.02/config/routes.rb test-plugin.03/config/routes.rb
1c1
< TestPlugin::Engine.routes.draw do
---
> Rails.application.routes.draw do
diff -r test-plugin.02/lib/test-plugin/engine.rb test-plugin.03/lib/test-plugin/engine.rb
3d2
<     isolate_namespace TestPlugin




# compare "mountable" (02) with "full & mountable" (04)
# -----------------------------------------------------------------------------

$ diff -r test-plugin.02 test-plugin.04

<no difference>




# compare "full" (03) with "full & mountable" (04)
# -----------------------------------------------------------------------------

$ diff -r test-plugin.03 test-plugin.04

Only in test-plugin.03/app/assets/javascripts/test-plugin: .gitkeep
Only in test-plugin.04/app/assets/javascripts/test-plugin: application.js
Only in test-plugin.03/app/assets/stylesheets/test-plugin: .gitkeep
Only in test-plugin.04/app/assets/stylesheets/test-plugin: application.css
Only in test-plugin.03/app/controllers: .gitkeep
Only in test-plugin.04/app/controllers: test-plugin
Only in test-plugin.03/app/helpers: .gitkeep
Only in test-plugin.04/app/helpers: test-plugin
Only in test-plugin.03/app/mailers: .gitkeep
Only in test-plugin.03/app/models: .gitkeep
Only in test-plugin.03/app/views: .gitkeep
Only in test-plugin.04/app/views: layouts
diff -r test-plugin.03/config/routes.rb test-plugin.04/config/routes.rb
1c1
< Rails.application.routes.draw do
---
> TestPlugin::Engine.routes.draw do
diff -r test-plugin.03/lib/test-plugin/engine.rb test-plugin.04/lib/test-plugin/engine.rb
2a3
>     isolate_namespace TestPlugin

สิ่งที่น่าสนใจเป็นพิเศษ (สำหรับฉัน) คือความจริงที่ว่าไม่มีความแตกต่างระหว่าง

rails plugin new test-plugin -T --mountable

และ

rails plugin new test-plugin -T --full --mountable

อาจเป็นเพราะ--fullมีความสำคัญมากกว่า--mountable?
Mankalas

8

ความเข้าใจของฉันเกี่ยวกับความแตกต่างคือเอ็นจิ้นเป็นเหมือนปลั๊กอินและเพิ่มฟังก์ชันการทำงานให้กับแอปพลิเคชันที่มีอยู่ ในขณะที่แอพที่ติดตั้งได้นั้นเป็นแอพพลิเคชั่นและสามารถยืนอยู่คนเดียว

ดังนั้นหากคุณต้องการเรียกใช้งานด้วยตัวเองหรือภายในแอปพลิเคชันอื่นคุณจะต้องสร้างแอปที่ติดตั้งได้ หากคุณตั้งใจให้มันเป็นส่วนเสริมของแอปพลิเคชั่นที่มีอยู่ แต่ไม่ได้รันด้วยตัวเองคุณจะทำให้มันเป็นเครื่องยนต์


2

ฉันเชื่อว่าความแตกต่างคือแอปที่ติดตั้งได้นั้นแยกออกจากแอปโฮสต์ดังนั้นจึงไม่สามารถแชร์คลาส - โมเดลตัวช่วยและอื่น ๆ ได้เนื่องจากแอป Mountable เป็นอุปกรณ์ปลายทางของ Rack (เช่นแอป Rack ในสิทธิ์ของตัวเอง )

คำเตือน: ฉันมีเหมือนส่วนใหญ่เพิ่งเริ่มเล่นกับ Rails 3.1


ตกลง สิ่งหนึ่งที่ดูแปลก ๆ ก็คือโดยค่าเริ่มต้น Engine จะให้โฟลเดอร์ "model" แก่คุณ แต่แอปที่ติดตั้งได้ไม่มี ฉันสงสัยว่า "แนวทางปฏิบัติที่ดีที่สุด" จะมีเครื่องกำเนิดไฟฟ้าที่สร้างแบบจำลองสำหรับแอปที่รวมอยู่ด้วยหรือไม่เนื่องจากดูเหมือนว่าคุณไม่ต้องการให้มีการโยกย้ายใด ๆ ในเครื่องยนต์ / สามารถพูดได้
Jeremy Raines
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.