การใช้ Rails 3.1 คุณใส่โค้ด JavaScript ของ“ หน้าเฉพาะ” ไว้ที่ไหน?


388

เพื่อความเข้าใจของฉัน JavaScript ทั้งหมดของคุณจะถูกรวมเป็น 1 ไฟล์ Rails ทำสิ่งนี้ตามค่าเริ่มต้นเมื่อเพิ่ม//= require_tree .ลงในapplication.jsไฟล์ Manifest ของคุณ

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

นอกจากนี้ยังไม่มีโอกาสที่จะเกิดรหัสที่ขัดแย้งกันได้หรือไม่

หรือคุณใส่scriptแท็กขนาดเล็กที่ด้านล่างของหน้าเว็บที่เพิ่งเรียกใช้เป็นวิธีการที่เรียกใช้โค้ดจาวาสคริปต์สำหรับหน้า?

คุณไม่ต้องการ require.js อีกต่อไปแล้วใช่ไหม

ขอบคุณ

แก้ไข : ฉันขอบคุณคำตอบทั้งหมด ... และฉันไม่คิดว่าพวกเขาจะได้รับปัญหาจริงๆ บางคนเกี่ยวกับการออกแบบและดูเหมือนจะไม่เกี่ยวข้อง ... และคนอื่น ๆ พูดถึงjavascript_include_tag... ที่ฉันรู้ว่ามีอยู่ (ชัด ๆ ... ) แต่มันจะปรากฏว่าทางรถไฟ 3.1 จะก้าวไปข้างหน้าเพื่อห่อหุ้มทั้งหมด JavaScript ของคุณเป็น 1 ไฟล์แทนที่จะโหลด JavaScript ที่ด้านล่างของแต่ละหน้า

ทางออกที่ดีที่สุดที่ฉันสามารถทำได้คือห่อคุณสมบัติบางอย่างในdivแท็กด้วยids หรือclasses ในรหัส JavaScript, คุณเพียงแค่ตรวจสอบว่าidหรือclassอยู่บนหน้าและถ้ามันเป็นคุณเรียกใช้รหัส JavaScript ที่เกี่ยวข้องกับมัน วิธีนี้หากองค์ประกอบแบบไดนามิกไม่ได้อยู่ในหน้ารหัส JavaScript ไม่ทำงาน - แม้ว่าจะรวมอยู่ในapplication.jsไฟล์ขนาดใหญ่ที่บรรจุโดย Sprockets

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

ฉันคิดว่านี่เป็นคำตอบที่แท้จริงสำหรับคำถามของฉัน


11
"ทาง Rails 3.1 ก้าวไปข้างหน้าคือห่อจาวาสคริปต์ทั้งหมดของคุณให้เป็น 1 ไฟล์แทนที่จะโหลด Javascript แต่ละอันที่ด้านล่างของแต่ละหน้า" - เพราะทีมหลักของ Rails คือและไม่เคยรู้มาก่อนเลยว่า เพื่อจัดการจาวาสคริปต์ โดยทั่วไปไฟล์ขนาดเล็กจะดีกว่า (ดูความคิดเห็นของฉันที่อื่น) เมื่อพูดถึง JavaScript ทาง Rails ไม่ค่อยถูกทาง (ยกเว้นไปป์ไลน์ของสินทรัพย์ซึ่งเตะตูดและให้กำลังใจ CoffeeScript)
Marnen Laibow-Koser

ดังนั้นคุณจะรวมไฟล์ js เฉพาะหน้าในทุกหน้า? ฉันคิดว่านั่นเป็นของเสียฉันเห็นด้วยกับคำตอบของ ClosedCowboy
gerky

1
คุณได้ดูคำตอบที่ยอมรับสำหรับคำถามนี้หรือไม่? stackoverflow.com/questions/6571753/…
rassom

1
@DutGRIFF ในคำอื่น ๆ : ไม่เป็นการดีที่สุดที่จะทำสิ่งต่าง ๆ ใน Rails ในกรณีนี้ (หรืออย่างน้อยก็อย่าใส่ทุกอย่างapplication.js) และอันที่จริงแล้วการอ้างอิงที่คุณให้มานั้นเป็นสาเหตุ: การดาวน์โหลดเป็น ส่วนที่ช้าที่สุดของกระบวนการดำเนินการ JS ไฟล์ขนาดเล็กจำนวนมากสามารถแคชได้มากกว่าไฟล์ขนาดใหญ่ ผู้คนที่ดูเหมือนจะไม่เข้าใจ Rails ดูเหมือนว่าคำแนะนำของพวกเขาจะไม่สอดคล้องกับหลักการที่พวกเขาพยายามที่จะยึดมั่นและดังนั้นคำแนะนำของพวกเขาไม่ควรดำเนินการอย่างจริงจัง
Marnen Laibow-Koser

1
@DutGRIFF ไม่ไฟล์ JS ขนาดใหญ่จะไม่เป็นสิ่งที่ดีแม้แต่ครั้งเดียวที่แคช ดูความคิดเห็นของฉันที่อื่นในหน้านี้: ไฟล์ขนาดเล็กสามารถกำหนดเป้าหมายเฉพาะหน้าได้ดีกว่าและสามารถแคชได้อย่างละเอียดยิ่งขึ้น ฉันไม่เห็นกรณีการใช้งานที่ดีใด ๆ สำหรับไฟล์ขนาดใหญ่เดียวจนกว่าจะมีไม่มีหน้ารหัสเฉพาะที่ทั้งหมด
Marnen Laibow-Koser

คำตอบ:


157

เอกสารท่อสินทรัพย์แนะนำวิธีการทำ JS เฉพาะตัวควบคุม:

ตัวอย่างเช่นถ้าProjectsControllerถูกสร้างขึ้นจะมีไฟล์ใหม่ที่และอื่นapp/assets/javascripts/projects.js.coffeeapp/assets/stylesheets/projects.css.scssคุณควรใส่ใด ๆ JavaScript หรือ CSS ที่ไม่ซ้ำกันในการควบคุมภายในไฟล์สินทรัพย์ของตนเช่นไฟล์เหล่านั้นจะสามารถโหลดเพียงสำหรับตัวควบคุมเหล่านี้ที่มีเส้นเช่นหรือ<%= javascript_include_tag params[:controller] %><%= stylesheet_link_tag params[:controller] %>

ลิงก์ไปที่: asset_pipeline


50
นี่เป็นวิธีที่หรูหราที่สุดในการทำ แต่คุณจะต้องลบบรรทัด // = require_tree ด้วย จาก the application.js.coffee
zsljulius

2
ฉันเห็นด้วยกับวิธีการนี้โดยสิ้นเชิง วิธีการอื่น ๆ ดูเหมือนจะเป็นเรื่องไร้สาระและยังคงจบลงด้วยการโหลดไฟล์ js ยักษ์ โปรเจ็กต์ที่กำลังทำงานอยู่มีมูลค่าเกือบ 2mb ของไฟล์ JS / ปลั๊กอิน ฯลฯ หลังจากที่รวมกัน / ย่อส่วน
Bill Garrison

2
ฉันค่อนข้างใหม่สำหรับ Rails แต่สำหรับฉันแล้วมันน่าจะเป็นพฤติกรรมเริ่มต้น
Ross Hambrick

12
สำหรับการควบคุมเฉพาะการกระทำฉันมีสิ่งนี้ในโครงร่างของฉันเนื่องจากไม่ใช่ทุกการกระทำสำหรับตัวควบคุมทุกตัวที่มี JS เฉพาะ page_specific_js = "#{params[:controller]}_#{params[:action]}"แล้ว; javascript_include_tag page_specific_js if Rails.application.assets.find_asset page_specific_js
Sujimichi

2
การกระทำเฉพาะของคอนโทรลเลอร์ยังคงลดน้อยลงหรือไม่? พวกเขาจะถูกเพิ่มลงในไฟล์ js เดียวที่สร้างโดยเฟืองหรือจะนำไปสู่การร้องขอหลายไฟล์สำหรับไฟล์เนื้อหาหรือไม่
เจสัน

77

สำหรับ js หน้าเฉพาะคุณสามารถใช้วิธีการแก้ปัญหาการ์เบอร์ไอริช

ดังนั้นโฟลเดอร์ javascripts ของ Rails ของคุณอาจมีลักษณะเช่นนี้สำหรับผู้ควบคุมสองคน - รถยนต์และผู้ใช้:

javascripts/
├── application.js
├── init.js
├── markup_based_js_execution
├── cars
   ├── init .js
   ├── index.js
   └── ...
└── users
    └── ...

และจาวาสคริปต์จะมีลักษณะเช่นนี้:

// application.js

//= 
//= require init.js
//= require_tree cars
//= require_tree users

// init.js

SITENAME = new Object();
SITENAME.cars = new Object;
SITENAME.users = new Object;

SITENAME.common.init = function (){
  // Your js code for all pages here
}

// cars/init.js

SITENAME.cars.init = function (){
  // Your js code for the cars controller here
}

// cars/index.js

SITENAME.cars.index = function (){
  // Your js code for the index method of the cars controller
}

และ markup_based_js_execution จะมีรหัสสำหรับวัตถุ UTIL และในการดำเนินการ UTIL ที่พร้อมใช้ DOM ใน DOM

และอย่าลืมใส่สิ่งนี้ลงในไฟล์เลย์เอาต์ของคุณ:

<body data-controller="<%= controller_name %>" data-action="<%= action_name %>">

ฉันยังคิดว่ามันจะดีกว่าที่จะใช้คลาสแทนdata-*คุณลักษณะสำหรับ css เฉพาะหน้าดีกว่า ดังที่ Jason Garber ได้กล่าวถึง: ตัวเลือก CSS เฉพาะหน้าเว็บอาจจะอึดอัดมาก (เมื่อคุณใช้data-*คุณลักษณะ)

ฉันหวังว่านี่จะช่วยคุณได้


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

@ tybro0103 ฉันคิดว่าจะใช้ลักษณะการทำงานนี้คุณต้องการที่จะเขียนสิ่งที่ชอบwindow.varForOneController='val'ในฟังก์ชั่น init คอนโทรลเลอร์นี้ นอกจากนี้ gon gem ยังสามารถช่วยได้ที่นี่ ( github.com/gazay/gon ) อาจมีวิธีแก้ไขอื่น ๆ
welldan97

1
@ welldan97 การลงคะแนนไม่ใช่สำหรับคำอธิบายของคุณ - ซึ่งยอดเยี่ยม - แต่เนื่องจากโครงสร้างการ์เบอร์ - ไอริชนั้นชั่วร้าย มันโหลด JS ทั้งหมดของคุณในทุกหน้าและขึ้นอยู่กับคลาสและรหัสในองค์ประกอบ <body> เพื่อเรียงลำดับสิ่งต่างๆ นั่นเป็นสัญญาณที่แน่นอนว่าต้องต่อสู้กับ DOM: ภายใต้สถานการณ์ปกติองค์ประกอบ <body> ไม่ควรต้องการคลาสหรือ ID เนื่องจากมีเพียงหนึ่งเอกสารในเอกสาร วิธีที่เหมาะสมในการทำเช่นนี้คือการลบ//= require_tree .และใช้ JavaScript เฉพาะหน้าเว็บ หากคุณพยายามอย่างแข็งขันที่จะไม่ทำสิ่งนั้นแสดงว่าคุณพยายามอย่างหนักในการฝึกฝน
Marnen Laibow-Koser

2
@ MarnenLaibow-Koser โดยส่วนตัวฉันเชื่อว่าการโหลด js ทั้งหมดในทุกหน้าเป็นสิ่งที่ดีสำหรับโครงการส่วนใหญ่เมื่อคุณรวม js ทั้งหมดไว้ในไฟล์เดียวและย่อให้เล็กสุด ฉันเชื่อว่าภาพรวมนั้นทำงานได้เร็วกว่าสำหรับผู้ใช้ อย่างน้อยมันก็มีความขัดแย้งกันมากกว่าหนึ่งไฟล์ js เทียบกับไฟล์อื่น ๆ (เช่นดูที่stackoverflow.com/questions/555696/… ) นอกจากนี้ยังไม่มีอะไรเลวร้ายในการใช้คลาสและรหัสบนร่างกายถ้ามันทำให้โค้ดง่ายขึ้นและเหมาะกับคุณ Modernizr ( modernizr.com ) ทำสิ่งนี้และ libs อื่น ๆ ด้วย
welldan97

2
@ MarnenLaibow-Koser ไปป์ไลน์สินทรัพย์ทางรถไฟสำหรับฉันดูเหมือนว่าเป็นผู้สมัครที่ดีสำหรับการเปรียบเทียบกับการรวบรวม โปรแกรมเมอร์เขียนจาวาสคริปต์ของพวกเขาในโมดูล decoupled ที่ดีและจากนั้นจะถูกรวมเข้าด้วยกันลดขนาดและเสิร์ฟ เช่นเดียวกับในกรณีของภาษาที่คอมไพล์แล้วจะมีโปรแกรมเมอร์ที่คิดว่าพวกเขาเป็นผู้นำในการคอมไพเลอร์ ... แต่ฉันคิดว่านี่ไม่ค่อยเป็นความจริง
Ziggy

65

ฉันเห็นว่าคุณตอบคำถามของคุณเอง แต่นี่เป็นอีกตัวเลือกหนึ่ง:

โดยพื้นฐานแล้วคุณกำลังตั้งสมมติฐานว่า

//= require_tree .

ต้องระบุ. มันไม่ใช่. รู้สึกอิสระที่จะลบมัน ในแอปพลิเคชันปัจจุบันของฉันสิ่งแรกที่ฉันทำกับ 3.1.x โดยสุจริตฉันสร้างไฟล์ JS ระดับบนสุดสามแบบ application.jsไฟล์ของฉันมีเพียง

//= require jquery
//= require jquery_ujs
//= require_directory .
//= require_directory ./api
//= require_directory ./admin

ด้วยวิธีนี้ฉันสามารถสร้างไดเรกทอรีย่อยด้วยไฟล์ JS ระดับบนสุดของตนเองซึ่งรวมเฉพาะสิ่งที่ฉันต้องการ

กุญแจคือ:

  1. คุณสามารถลบได้require_tree- Rails ให้คุณเปลี่ยนสมมติฐานที่ตั้งไว้
  2. ไม่มีอะไรพิเศษเกี่ยวกับชื่อapplication.js- ไฟล์ใด ๆ ในassets/javascriptไดเรกทอรีย่อยสามารถรวมคำสั่งประมวลผลล่วงหน้าด้วย//=

หวังว่าจะช่วยและเพิ่มรายละเอียดในคำตอบของ ClosedCowboy

Sujal


8
+1 นี่เป็นเรื่องดีที่รู้ว่าสำหรับมือใหม่อย่างฉัน ฉันจะให้ +2 ถ้าฉันทำได้
jrhorn424

5
@sujal แน่นอน ทีมหลักของ Rails มีชื่อเสียงในด้านการจัดการ JavaScript อย่างสุดซึ้ง อย่าลังเลที่จะรับคำแนะนำของพวกเขาและเพียงใช้ส่วนที่ดีของไปป์ไลน์ :)
Marnen Laibow-Koser

1
ขอบคุณมากสำหรับคำแนะนำนี้ ฉันไม่มีไฟล์ JS "ระดับบนสุด" หลายรายการขึ้นอยู่กับโมดูลของแอพของฉัน ทำได้ดี.
elsurudo

1
+1 จุดสำคัญที่นี่สำหรับฉันคือคุณสามารถแทนที่//= require_tree .ด้วย//= require_directory .เพื่อให้คุณสามารถเก็บไฟล์ที่มีอยู่ทั้งหมดที่พวกเขาอยู่และสร้างไดเรกทอรีใหม่สำหรับไฟล์เฉพาะหน้า
zelanix

41

ตัวเลือกอื่น: ในการสร้างไฟล์เฉพาะหน้าหรือรุ่นคุณสามารถสร้างไดเรกทอรีภายในassets/javascripts/โฟลเดอร์ของคุณ

assets/javascripts/global/
assets/javascripts/cupcakes
assets/javascripts/something_else_specific

application.jsไฟล์หลักของคุณสามารถกำหนดค่าให้โหลดไฟล์global/ได้ หน้าเฉพาะหรือกลุ่มของหน้าอาจมีรายการของตนเองซึ่งโหลดไฟล์จากไดเรกทอรีเฉพาะของตนเอง เฟืองจะรวมไฟล์ที่โหลดเข้าapplication.jsกับไฟล์เฉพาะหน้าของคุณ โดยอัตโนมัติ

เทคนิคนี้สามารถใช้สำหรับstyle_sheets/เช่นกัน


13
คุณทำให้ฉันอยากได้คัพเค้กตอนนี้ .. Dangit!
Chuck Bergeron

ฉันชอบวิธีนี้มาก ปัญหาเดียวที่ฉันมีคือว่ารายการพิเศษเหล่านั้นจะไม่ถูกบีบอัด / อัปเดต พวกเขาจะรวบรวมอย่างถูกต้องว่า มีวิธีแก้ไขหรือฉันขาดอะไรไปหรือเปล่า?
clst

1
หมายความว่าเบราว์เซอร์โหลดไฟล์ js หนึ่งไฟล์นั่นคือการรวมกันของไฟล์เฉพาะทั่วโลก + หน้า?
lulalala

คุณช่วยดูคำถามของฉันได้ไหมถ้ามี stackoverflow.com/questions/17055213/…
Maximus S

1
@clst ฉันเชื่อว่านี่เป็นคำตอบที่คุณกำลังมองหา: ไกด์นำเที่ยว rubyonrails.org/asset_pipeline.html#precompiling-assets
FrontierPsycho

23

ฉันขอขอบคุณคำตอบทั้งหมด ... และฉันไม่คิดว่าพวกเขาจะได้รับปัญหาจริงๆ บางคนเกี่ยวกับการออกแบบและดูเหมือนจะไม่เกี่ยวข้อง ... และคนอื่น ๆ ก็พูดถึงjavascript_include_tag ... ที่ฉันรู้ว่ามีอยู่ (ชัด ๆ ... ) แต่มันจะปรากฏว่าทาง Rails 3.1 จะก้าวไปข้างหน้าเพื่อห่อหุ้มทั้งหมด Javascript ของคุณเป็น 1 ไฟล์แทนที่จะโหลด Javascript ที่ด้านล่างของแต่ละหน้า

ทางออกที่ดีที่สุดที่ฉันสามารถทำได้คือห่อคุณสมบัติบางอย่าง divแท็กด้วยids หรือclasses ในรหัสจาวาสคริปต์ จากนั้นคุณเพียงแค่ตรวจสอบว่าidหรือclassอยู่ในหน้าและถ้าเป็นคุณเรียกใช้รหัสจาวาสคริปต์ที่เกี่ยวข้องกับมัน วิธีนี้หากองค์ประกอบแบบไดนามิกไม่ได้อยู่ในหน้ารหัส javascript จะไม่ทำงาน - แม้ว่าจะรวมอยู่ในapplication.jsไฟล์ขนาดใหญ่ที่บรรจุโดย Sprockets

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

ฉันคิดว่านี่เป็นคำตอบที่แท้จริงสำหรับคำถามของฉัน


แต่คุณต้องการ<script>แท็กด้วยตนเองเหล่านั้นจริงๆ ใช่คลาสและรหัสเป็นส่วนหนึ่งของคำตอบ แต่ผู้ใช้ไม่สามารถโหลด JavaScript ที่หน้านั้นไม่จำเป็นต้องใช้
Marnen Laibow-Koser

4
@ MarnenLaibow-Koser เหตุผลที่ไม่เพิ่มแท็กสคริปต์ด้วยตนเองลงในหน้าเฉพาะแต่ละหน้าคือคุณต้องดาวน์โหลดเนื้อหาสคริปต์นั้นในทุก ๆ การดูหน้าเว็บ หากคุณสามารถบรรจุ javascript ทั้งหมดลงใน application.js โดยใช้
ไพพ์

@jakeonrails "เหตุผลที่ไม่เพิ่มแท็กสคริปต์ด้วยตนเองลงในหน้าเว็บที่ไม่ซ้ำกันแต่ละหน้าก็คือคุณต้องดาวน์โหลดเนื้อหาสคริปต์นั้นในทุก ๆ การดูหน้า" - ค่อนข้างผิด สคริปต์จะถูกดาวน์โหลดหนึ่งครั้งจากนั้นจะดึงข้อมูลจากแคชของเบราว์เซอร์ตามคำขอเพิ่มเติม "หากคุณสามารถจัดทำจาวาสคริปต์ทั้งหมดลงใน application.js โดยใช้ขั้นตอนการชำระสินทรัพย์ผู้ใช้จะดาวน์โหลดสคริปต์เหล่านั้นเพียงครั้งเดียวเท่านั้น" - จริง แต่ด้วยค่าใช้จ่ายของรหัสที่ไม่จำเป็นจำนวนมาก หากคุณสามารถจัดโครงสร้าง JS ของคุณเป็นไฟล์ขนาดเล็กจำนวนมากแทนที่จะเป็นไฟล์ขนาดใหญ่คุณจะได้รับผลประโยชน์การแคชโดยไม่ต้องใช้รหัสที่ไม่จำเป็น
Marnen Laibow-Koser

1
@ MarnenLaibow-Koser ฉันคิดว่าคงจะเป็นการดีกว่าที่จะบอกว่าถ้าคุณรวมทุกอย่างไว้ในสคริปต์เดียวผู้ใช้ของคุณจะต้องดาวน์โหลด 1 สคริปต์สำหรับหน้าใด ๆ ในไซต์ของคุณ หากคุณมีหลายสคริปต์สำหรับส่วนต่าง ๆ ของแอปของคุณผู้ใช้จะต้องดาวน์โหลดมากกว่าหนึ่งสคริปต์อย่างชัดเจน แน่นอนว่าทั้งสองวิธีนี้จะถูกแคช แต่ในกรณีส่วนใหญ่ (แอปขนาดเล็กขนาดกลาง) ซึ่งให้บริการแอปพลิเคชั่นเดียวหนึ่งครั้งจะมีประสิทธิภาพมากขึ้นสำหรับการดาวน์โหลด การแยกวิเคราะห์ JS อาจเป็นอีกเรื่องหนึ่งขึ้นอยู่กับว่าคุณให้บริการอะไร
jakeonrails

1
@Ziggy นอกจากนี้หากไฟล์ขนาดเล็กถูกใช้เฉพาะใน 8 หน้าจาก 100 หน้าทำไมรหัสควรนั่งในแคชของผู้ใช้ตลอดเวลา? ดีกว่าที่จะทิ้งสิ่งที่ไม่ต้องการ
Marnen Laibow-Koser

16

ฉันรู้ว่าฉันมางานปาร์ตี้ช้าไปหน่อย แต่ฉันอยากจะแก้ปัญหาที่ฉันเคยใช้เมื่อไม่นานมานี้ อย่างไรก็ตามให้ฉันก่อนพูดถึง ...

The Rails 3.1 / 3.2 Way (ไม่ครับฉันไม่ชอบ)

ดู: http://guides.rubyonrails.org/asset_pipeline.html#how-to-use-the-asset-pipeline

ฉันรวมสิ่งต่อไปนี้เพื่อความครบถ้วนในคำตอบนี้และเพราะมันไม่ใช่วิธีแก้ปัญหาที่ไม่สามารถคาดเดาได้ ... ถึงแม้ว่าฉันจะไม่สนใจมันมากนัก

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

หากต้องการรวมรหัสเฉพาะของตัวควบคุมจะเพิ่มสิ่งต่อไปนี้ลงในมุมมอง

<%= javascript_include_tag params[:controller] %>

ฉันเกลียดวิธีนี้ แต่มันอยู่ที่นั่นและมันก็รวดเร็ว สมมุติว่าคุณสามารถเรียกไฟล์เหล่านี้ได้เช่น "people-index.js" และ "people-show.js" จากนั้นใช้บางอย่างที่ต้องการ"#{params[:controller]}-index"รับโซลูชันแบบมุมมอง อีกครั้งแก้ไขอย่างรวดเร็ว แต่มันก็ไม่ได้นั่งกับฉัน

วิธีการเก็บข้อมูลของฉัน

โทรหาฉันบ้า แต่ฉันต้องการให้ JS รวบรวมและย่อขนาดเป็น application.js ทั้งหมดเมื่อฉันปรับใช้ ฉันไม่ต้องการที่จะจำรวมไฟล์ straggler เล็ก ๆ เหล่านี้ทั่วสถานที่

ฉันโหลด JS ทั้งหมดของฉันในไฟล์เดียวที่เบราว์เซอร์แคชขนาดกะทัดรัดเร็ว ๆ นี้จะเป็น หากบางส่วนของ application.js ของฉันต้องถูกไล่ออกบนหน้าเว็บฉันปล่อยให้ HTML บอกฉันไม่ใช่ Rails

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

<input name="search" data-jstag="auto-suggest hint" />

ในแต่ละหน้าฉันใช้- แทรกเมธอดไลบรารี JS ที่ต้องการที่นี่เพื่อรันโค้ดเมื่อ DOM โหลดเสร็จแล้ว รหัส bootstrapping นี้ทำการกระทำดังต่อไปนี้:

  1. ทำซ้ำองค์ประกอบทั้งหมดใน DOM ที่ทำเครื่องหมายด้วย data-jstag
  2. สำหรับแต่ละองค์ประกอบแบ่งค่าคุณลักษณะบนพื้นที่สร้างอาร์เรย์ของสตริงแท็ก
  3. สำหรับสตริงแท็กแต่ละรายการให้ทำการค้นหาใน Hash สำหรับแท็กนั้น
  4. หากพบคีย์ที่ตรงกันให้เรียกใช้ฟังก์ชันที่เกี่ยวข้องโดยส่งผ่านองค์ประกอบเป็นพารามิเตอร์

ดังนั้นบอกว่าฉันมีคำนิยามต่อไปนี้อยู่ที่ไหนสักแห่งใน application.js ของฉัน:

function my_autosuggest_init(element) {
  /* Add events to watch input and make suggestions... */
}

function my_hint_init(element) {
  /* Add events to show a hint on change/blur when blank... */
  /* Yes, I know HTML 5 can do this natively with attributes. */
}

var JSTags = {
  'auto-suggest': my_autosuggest_init,
  'hint': my_hint_init
};

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

นอกจากจะมีการติดแท็กองค์ประกอบบางอย่างด้วย data-jstag="auto-suggest"รหัสที่แนะนำโดยอัตโนมัติจะไม่มีไฟอย่างไรก็ตามมันอยู่ที่นั่นเสมอลดขนาดและในที่สุดก็จะเก็บไว้ใน application.js ของฉันสำหรับช่วงเวลาที่ฉันต้องการบนหน้า

หากคุณต้องการส่งพารามิเตอร์เพิ่มเติมไปยังฟังก์ชัน JS ที่ติดแท็กของคุณคุณจะต้องใช้ความคิดสร้างสรรค์บางอย่าง เพิ่มแอ็ตทริบิวต์ data-paramter, มาพร้อมกับไวยากรณ์ชนิดของพารามิเตอร์หรือใช้วิธีไฮบริด

แม้ว่าฉันจะมีเวิร์กโฟลว์ที่ซับซ้อนบางอย่างที่ดูเหมือนว่าตัวควบคุมเฉพาะฉันจะสร้างไฟล์ไว้ในโฟลเดอร์ lib ของฉันบรรจุลงใน application.js และติดแท็กด้วยสิ่งต่าง ๆ เช่น 'new-things-wizard' เมื่อ bootstrap ของฉันไปถึงแท็กนั้นตัวช่วยสร้างแฟนซีที่ดีของฉันจะถูกสร้างและเรียกใช้ มันทำงานสำหรับมุมมองของตัวควบคุมนั้นเมื่อจำเป็น แต่ไม่ได้เชื่อมโยงกับตัวควบคุม ในความเป็นจริงถ้าฉันรหัสตัวช่วยสร้างของฉันถูกต้องฉันอาจสามารถให้ข้อมูลการกำหนดค่าทั้งหมดในมุมมองและดังนั้นจึงสามารถใช้ตัวช่วยสร้างของฉันอีกครั้งในภายหลังสำหรับตัวควบคุมอื่น ๆ ที่ต้องการ

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


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

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับเอฟเฟกต์เชิงปฏิบัติของขั้นตอนการรวบรวมที่ฉันกำลังพูดถึงให้ดูที่คำอธิบาย 37 สัญญาณของวิธีที่ pjax ส่งผลกระทบต่อ Basecamp ถัดไป: 37signals.com/svn/posts/ …
sujal

นั่นเป็นประเด็นที่ยุติธรรม หลังจากอ่านบทความและมองย้อนกลับไปในโครงการที่ฉันใช้วิธีแก้ปัญหาข้างต้นแล้วฉันก็รู้ว่าฉันเขียนเหมือนเดิมว่า "ส่ง HTML ที่เปลี่ยนแปลงไป" ที่พวกเขาพูดถึงในบทความ การรวบรวม JS ซ้ำบ่อยครั้งไม่ได้เป็นปัญหาในโครงการของฉันเพราะสิ่งนั้น ขั้นตอนการรวบรวมเป็นสิ่งที่ฉันจะระลึกไว้เสมอเมื่อฉันทำงานบนไซต์ที่มุ่งเน้น "แอปพลิเคชันเดสก์ท็อป" น้อยลง
Ryan

2
Downvoting สำหรับ "Call me crazy แต่ฉันต้องการให้ JS ของฉันรวบรวมและย่อขนาดลงใน application.js เมื่อฉันปรับใช้" คุณไม่ต้องการสิ่งนี้จริงๆเพราะมันทำให้ผู้ใช้โหลด JavaScript ที่เขาไม่ต้องการและทำให้ตัวจัดการของคุณมองหาคุณลักษณะที่ไม่ได้อยู่ที่นั่น การมีทุกอย่างใน app.js เป็นสิ่งที่ดึงดูดและ Rails ทำให้มันง่าย แต่สิ่งที่ต้องทำคือการปรับใช้ JavaScript ให้ดีขึ้น
Marnen Laibow-Koser

คุณมีสิทธิ์ที่จะมีความคิดเห็นที่ต่างออกไป ... และคุณมีสิทธิ์ที่จะลงคะแนนให้กับความคิดเห็นที่ต่างออกไป อย่างไรก็ตามจะเป็นการดีหากได้เห็นเหตุผลว่าทำไมไฟล์ขนาดใหญ่และแคชหนึ่งไฟล์จึงด้อยกว่าการบังคับให้มีการร้องขอ HTTP หลายรายการเพื่อคว้า JS แบบโมดูลาร์ นอกจากนี้คุณเข้าใจผิดเกี่ยวกับขั้นตอนการค้นหาตัวจัดการ ค่าแท็กจะไม่ถูกค้นหา ทำการค้นหาเพียงครั้งเดียวเท่านั้นและจะดึงองค์ประกอบทั้งหมดที่มีคุณลักษณะ data-jstag มันไม่ได้ค้นหาด้วยชื่อแท็กมันแค่ค้นหาองค์ประกอบทั้งหมดที่มีแท็กแล้วทำให้วัตถุที่ต้องการเป็นอินสแตนซ์
Ryan

7

สิ่งนี้ได้รับการตอบรับและยอมรับมานานแล้ว แต่ฉันคิดวิธีแก้ปัญหาของตัวเองตามคำตอบเหล่านี้และประสบการณ์ของฉันกับ Rails 3+

ไปป์ไลน์ของสินทรัพย์นั้นหวาน ใช้มัน.

ก่อนอื่นในapplication.jsไฟล์ของคุณลบ//= require_tree.

จากนั้นในการapplication_controller.rbสร้างวิธีการช่วยเหลือของคุณ:

helper_method :javascript_include_view_js //Or something similar

def javascript_include_view_js
    if FileTest.exists? "app/assets/javascripts/"+params[:controller]+"/"+params[:action]+".js.erb"
        return '<script src="/assets/'+params[:controller]+'/'+params[:action]+'.js.erb" type="text/javascript"></script>'
    end
end

จากนั้นในapplication.html.erbไฟล์เลย์เอาต์ของคุณให้เพิ่มตัวช่วยใหม่ของคุณในจาวาสคริปต์ที่มีอยู่ซึ่งนำหน้าด้วยตัวrawช่วย:

<head>
    <title>Your Application</title>
    <%= stylesheet_link_tag "application", :media => "all" %>
    <%= javascript_include_tag "application" %>
    <%= raw javascript_include_view_js %>
</head>

Voila ตอนนี้คุณสามารถสร้างจาวาสคริปต์เฉพาะสำหรับดูได้อย่างง่ายดายโดยใช้โครงสร้างไฟล์เดียวกับที่คุณใช้ทุกที่ใน Rails เพียงติดไฟล์ของคุณapp/assets/:namespace/:controller/action.js.erb!

หวังว่าจะช่วยคนอื่น!


1
สิ่งนี้จะทำให้เกิดปัญหาหลังจากที่สินทรัพย์ถูกคอมไพล์แล้วและเวลารันไทม์<%= raw ... %>จะส่งคืน 404 หรือไม่?
Nishant

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

1
@DeborahSpeece ไปป์ไลน์สินทรัพย์สร้างไฟล์ที่ไม่ควรใช้เมื่อใด คุณสับสนท่อส่งของสินทรัพย์ (ดี) กับrequire_tree /(ไม่ดี) หรือไม่
Marnen Laibow-Koser

6

คุณสามารถเพิ่มบรรทัดนี้ในไฟล์เลย์เอาต์ของคุณ (เช่น application.html.erb) เพื่อโหลดไฟล์จาวาสคริปต์เฉพาะตัวควบคุม (บรรทัดที่สร้างขึ้นเมื่อคุณสร้างคอนโทรลเลอร์) โดยอัตโนมัติ:

<%= javascript_include_tag params[:controller] %>

คุณสามารถเพิ่มบรรทัดเพื่อโหลดไฟล์สคริปต์โดยอัตโนมัติในแบบต่อการกระทำ

<%= javascript_include_tag params[:controller] + "/" + params[:action] %>

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


6
<%= javascript_include_tag params[:controller] %>

2
ดูเหมือนว่าจะสามารถตอบคำถามได้ คุณช่วยเพิ่มคำตอบลงไปในเนื้อหนังได้ไหม?


5

LoadJSอัญมณีเป็นตัวเลือกอื่น:

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

https://github.com/guidomb/loadjs


3

คำตอบของฟิลิปค่อนข้างดี นี่คือรหัสที่จะทำให้มันทำงาน:

ใน application.html.erb:

<body class="<%=params[:controller].parameterize%>">

สมมติว่าตัวควบคุมของคุณเรียกว่าโครงการที่จะสร้าง:

<body class="projects">

จากนั้นใน projects.js.coffee:

jQuery ->
  if $('body.projects').length > 0  
     $('h1').click ->
       alert 'you clicked on an h1 in Projects'

Downvoting: โซลูชันใด ๆ ที่ทำให้คลาส<body>เป็นipso factoไม่ถูกต้อง ดูความคิดเห็นของฉันที่อื่นในหน้านี้
Marnen Laibow-Koser

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

2

มีการรวม JavaScript เมื่อคุณบอก Rails (Sprockets) เพื่อรวม


แน่นอน. ฉันเดาว่าฉันถามเพราะค่าเริ่มต้นของ Rails รวมทุกอย่างในโฟลเดอร์ ... ซึ่งหมายความว่าดาวิดตั้งใจให้คุณทำเช่นนั้น แต่เหมือนที่ฉันพูดในความคิดเห็นอื่นที่ @rubyprince ฉันไม่แน่ใจเกี่ยวกับการดำเนินการเมื่อมันทำเช่นนี้ ฉันคิดว่าฉันต้องปิดการใช้งาน//= require_tree .?
Fire Emblem

@FireEmblem ใช่ require_tree .มักเป็นความคิดที่ไม่ดี
Marnen Laibow-Koser

2

นี่คือวิธีที่ฉันแก้ไขปัญหาการใส่สไตล์: (ขอโทษ Haml)

%div{:id => "#{params[:controller].parameterize} #{params[:view]}"}
    = yield

วิธีนี้ฉันจะเริ่มต้นเฉพาะไฟล์. csssassทั้งหมดด้วย:

#post
  /* Controller specific code here */
  &#index
    /* View specific code here */
  &#new
  &#edit
  &#show

วิธีนี้คุณสามารถหลีกเลี่ยงการปะทะใด ๆ ได้อย่างง่ายดาย เมื่อพูดถึงไฟล์. jscoffeeคุณสามารถเริ่มต้นองค์ประกอบต่างๆเช่น

$('#post > #edit') ->
  $('form > h1').css('float', 'right')

หวังว่านี่จะช่วยได้บ้าง


1
โปรดอ่านบิตสุดท้ายอีกครั้งโปรดจาวาสคริปต์ที่คุณสามารถใช้ประโยชน์จากโครงสร้างเดียวกันที่ใช้สำหรับ stylesheets สำหรับการเริ่มต้นฟังก์ชั่นการดูที่เฉพาะเจาะจง
zeeraw

$('#post > #edit') ->ดูเหมือนว่าฟิลิปจะไม่ถูกต้อง คุณกำหนดขอบเขต jQuery ให้ทำงานภายในขอบเขตได้อย่างไร
Ramon Tayag

2
เมื่อเร็ว ๆ นี้ฉันเริ่มโหลดจาวาสคริปต์และสไตล์ชีทเฉพาะของคอนโทรลเลอร์ทั้งหมดโดยเรียกสิ่งนี้ใน application.html.haml; = javascript_include_tag "application"และ= javascript_include_tag params[:controller]ด้วยวิธีนี้ฉันสามารถเก็บรหัสจาวาสคริปต์ไว้โดยไม่ต้องระบุขอบเขตภายในไฟล์
zeeraw


2

ฉันเห็นด้วยกับคำตอบของคุณเพื่อตรวจสอบว่ามีตัวเลือกนั้นใช้หรือไม่:

if ($(selector).length) {
    // Put the function that does not need to be executed every page
}

(ไม่เห็นใครเพิ่มโซลูชันจริง)


2

ฉันไม่เห็นคำตอบที่นำมารวมกันและวางไว้เพื่อคุณ ดังนั้นฉันจะพยายามใส่meleyal , sujal (a la ClosureCowboy ) ส่วนแรกของคำตอบของ Ryanและแม้แต่คำสั่งที่กล้าหาญของ Galเกี่ยวกับ Backbone.js ... ทั้งหมดเข้าด้วยกันในแบบที่สั้นและชัดเจน และใครจะรู้ฉันอาจพบกับMarnen Laibow-Koserความต้องการ

ตัวอย่างการแก้ไข

assets / javascripts / application.js

//= require jquery
//= require jquery_ujs
//= require lodash.underscore.min
...


views / layouts / application.html.erb

  ...
  </footer>

  <!-- Javascripts ================================================== -->
  <!-- Placed at the end of the document so the pages load faster -->
  <%= javascript_include_tag "application" %>
  <%= yield :javascript %>

</body>
</html>


views / foo / index.html.erb

...
<% content_for :javascript do %>
  <%= javascript_include_tag params[:controller] %>
<% end %>


assets / javascripts / foo.js

//= require moment
//= require_tree ./foostuff


assets / javascripts / foostuff / foothis.js.coffee

alert "Hello world!"


คำอธิบายสั้น ๆ

  • ลบออก//= require_tree .จากapplication.jsและแสดงเฉพาะ JS ที่แต่ละหน้าแชร์

  • สองบรรทัดที่แสดงด้านบนในapplication.html.erbบอกหน้าที่จะรวม application.js และ JS เฉพาะเพจของคุณ

  • สามบรรทัดที่แสดงด้านบนในindex.html.erbบอกมุมมองของคุณให้มองหา JS เฉพาะหน้าเว็บและรวมไว้ในพื้นที่ผลตอบแทนที่ตั้งชื่อชื่อว่า ": javascript" (หรือสิ่งที่คุณต้องการตั้งชื่อ) ในตัวอย่างนี้คอนโทรลเลอร์คือ "foo" ดังนั้น Rails จะพยายามรวม "foo.js" ในส่วน: javascript ที่ให้ผลตอบแทนในโครงร่างของแอปพลิเคชัน

  • แสดงรายการ JS เฉพาะหน้าเว็บของคุณในfoo.js (หรือชื่ออะไรก็ได้ที่คอนโทรลเลอร์) ทำรายการไลบรารีทั่วไปต้นไม้ไดเรกทอรีอะไรก็ได้

  • ทำให้ JS เฉพาะเพจที่กำหนดเองของคุณอยู่ในที่ที่คุณสามารถอ้างอิงได้ง่ายนอกเหนือจาก JS ที่กำหนดเองอื่น ๆ ของคุณ ในตัวอย่างนี้ foo.js ต้องใช้ต้นไม้ foostuff เพื่อใส่ JS กำหนดเองของคุณมีเช่นfoothis.js.coffee

  • ไม่มีกฎที่ยากที่นี่ อย่าลังเลที่จะเคลื่อนย้ายสิ่งต่าง ๆ รอบ ๆ และอาจสร้างขอบเขตผลผลิตที่หลากหลายของชื่อต่าง ๆ ในเค้าโครงต่าง ๆ ถ้าจำเป็น นี่เป็นเพียงขั้นตอนแรกที่เป็นไปได้ (ฉันไม่ได้ทำอย่างนี้เหมือนกันเพราะเราใช้ Backbone.js ฉันอาจเลือกวาง foo.js ลงในโฟลเดอร์ที่ชื่อว่า foo แทนที่จะเป็น foostuff แต่ยังไม่ได้ตัดสินใจ)

หมายเหตุ

คุณสามารถทำสิ่งที่คล้ายกันด้วย CSS และ <%= stylesheet_link_tag params[:controller] %>นี่คือเกินขอบเขตของคำถาม

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


ดูเหมือนว่าจะไปฉันจะดูว่าฉันสามารถนำไปใช้ในแอพของฉันเองได้หรือไม่ขอบคุณสำหรับคำตอบอย่างละเอียด
martincarlin87

1

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

$(document).ready(function() {
   if(window.location.pathname.indexOf('/yourpage') != -1) {
          // the javascript you want to execute
   }
}

สิ่งนี้ยังอนุญาตให้โหลด js ทั้งหมดโดย rails 3.x ในแพ็คเกจขนาดเล็กหนึ่งแพค แต่ไม่สร้างโอเวอร์เฮดมากหรือมีข้อขัดแย้งใด ๆ กับเพจที่ไม่ได้มีเจตนาให้ js


1

คำตอบของ ryguy เป็นคำตอบที่ดีแม้ว่าจะถูกลดระดับลงเป็นจุดลบก็ตาม

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

ใน show.html.erb คุณจะมีสิ่งต่อไปนี้:

<% provide :javascript do %>
  <%= javascript_include_tag do %>
    (new app.views.ProjectsView({el: 'body'})).render();
  <% end %>
<% end do %>

และในไฟล์เลย์เอาต์ของคุณคุณจะต้อง:

<%= yield :javascript %>

downvoting JavaScript แบบอินไลน์ไม่ใช่ความคิดที่ดี แม้ว่ามันจะเป็นรหัสกาว แต่ก็ควรอยู่ในไฟล์ภายนอก
Marnen Laibow-Koser

1

ย้ายไฟล์ของคุณ commom JS ทั้งหมดไปยังโฟลเดอร์ย่อยเช่น 'app / สินทรัพย์ javascript / / ระดับโลก' จากนั้นใน application.js ที่ปรับเปลี่ยนสายไป//= require_tree .//= require_tree ./global

ตอนนี้คุณมีอิสระที่จะวาง JS เฉพาะตัวควบคุมของคุณลงในรูท 'แอพ / สินทรัพย์ / javascript /' และพวกมันจะไม่รวมอยู่ใน JS ที่คอมไพล์แล้วจะถูกใช้เมื่อคุณเรียกพวกมันผ่านทาง= javascript_include_tagคอนโทรลเลอร์ / มุมมองของคุณ


ไม่เป็นไร crapload ของ JavaScript ที่โหลดหนึ่งหน้า ไม่สำคัญว่าจะถูกแคชหรือไม่
jackyalcine

1

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

%body{'data-page' => "#{controller}:#{action}" }

จากนั้นมีการปิดเพียงครั้งเดียวและคำสั่งสลับในdispatcher.js.coffeeไฟล์ของคุณในโฟลเดอร์ javascripts ดังนี้:

$ ->
  new Dispatcher()

class Dispatcher
  constructor: ->
    page = $('body').attr('data-page')
    switch page
      when 'products:index'
        new Products() 
      when 'users:login'
        new Login()

สิ่งที่คุณต้องทำในแต่ละไฟล์ (พูดproducts.js.coffeeหรือlogin.js.coffeeตัวอย่าง) คือล้อมรอบพวกเขาในชั้นเรียนแล้วทำให้เป็นสัญลักษณ์ระดับโลกที่เป็นสากลเพื่อให้คุณสามารถเข้าถึงได้ในดิสแพตเชอร์:

class Products
  constructor: ->
    #do stuff
@Products = Products

Gitlab มีหลายตัวอย่างของสิ่งนี้ที่คุณอาจอยากลองทำในกรณีที่คุณอยากรู้ :)


1

โครงการPalomaเสนอวิธีการที่น่าสนใจในการจัดการรหัสจาวาสคริปต์เฉพาะหน้า

ตัวอย่างการใช้งานจากเอกสาร:

var UsersController = Paloma.controller('Users');

// Executes when Rails User#new is executed.
UsersController.prototype.new = function(){
   alert('Hello Sexy User!' );
};

1

ขั้นตอนที่ 1. ลบ require_tree ใน application.js และ application.css ของคุณ

ขั้นตอนที่ 2. แก้ไข application.html.erb ของคุณ (ตามค่าเริ่มต้นของราง) ในโฟลเดอร์เค้าโครง เพิ่ม "params [: controller]" ในแท็กต่อไปนี้

<%= stylesheet_link_tag    'application', params[:controller], media: 'all', 'data-turbolinks-track' => true %>

<%= javascript_include_tag 'application', params[:controller], 'data-turbolinks-track' => true %>

ขั้นตอนที่ 3 เพิ่มไฟล์ใน config / initializers / assets.rb

%w( controller_one controller_two controller_three ).each do |controller|
  Rails.application.config.assets.precompile += ["#{controller}.js", "#{controller}.js.coffee", "#{controller}.css", "#{controller}.scss"]
end

การอ้างอิง: http://theflyingdeveloper.com/controller-specific-assets-with-rails-4/


ในขณะที่สิ่งนี้อาจตอบคำถามในทางทฤษฎีมันก็ควรที่จะรวมส่วนสำคัญของคำตอบที่นี่และให้ลิงค์สำหรับการอ้างอิง
Bhargav Rao

0

ฉันยังไม่ได้ลอง แต่ดูเหมือนว่าจะเป็นจริง:

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

  • หากคุณต้องการแยกไฟล์ออกจากชุดใหญ่ของ javascript คุณจะเข้าไปในไฟล์ config / sprockets.yml และแก้ไข source_files ตามลำดับ จากนั้นคุณจะรวมไฟล์ใด ๆ ที่คุณยกเว้นเมื่อจำเป็น


การยกเว้นไฟล์หรือใช้จาวาสคริปต์ที่กำหนดเองบนหน้าเว็บนั้นเป็น "วิธีที่ถูกต้อง" ใช่หรือไม่? นั่นเป็นวิธีที่ดาวิดตั้งใจให้คนใช้หรือไม่?
Fire Emblem

@FireEmblem ฉันไม่สนใจสิ่งที่ดาวิดตั้งใจเพราะฉันไม่คิดว่าเดวิดเข้าใจวิธีการจัดระเบียบ JavaScript อย่างถูกต้อง
Marnen Laibow-Koser

0

ฉันไม่ได้ก่อนหน้านี้ใช้วิธีการนี้: http://theflyingdeveloper.com/controller-specific-assets-with-rails-4/ ง่ายมากอาศัยการควบคุมเพื่อเลือก js ที่เหมาะสมในการโหลด


0

ฉันรวมคำตอบลงไป:

แอพลิเคชันผู้ช่วย:

module ApplicationHelper
  def js_page_specific_include
    page_specific_js = params[:controller] + '_' + params[:action]
    if Rails.application.assets.find_asset(page_specific_js).nil?
      javascript_include_tag 'application', 'data-turbolinks-track' => true
    else
      javascript_include_tag 'application', page_specific_js, 'data-turbolinks-track' => true
    end
  end
end

รูปแบบ / application.html.haml:

 <!DOCTYPE html>
%html{lang: 'uk'}
  %head   
    = stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true
   bla-bla-bla
    = js_page_specific_include   
   bla-bla-bla  

0

อย่างแรก: ลบออก\\=require_treeจาก application.js ข้อที่สอง: รหัส JS ทั้งหมดของคุณจะต้องได้รับการจัดสรรที่/app/assets/javascritptและโค้ด CSS ทั้งหมดของคุณจะต้องได้รับการจัดสรรที่/app/assets/stylesheets


-2

ต่อไปนี้นำไปสู่จาก Ryan นี่คือสิ่งที่ฉันได้ทำ -

application.js.coffee

$ ->
    view_method_name = $("body").data("view") + "_onload"
    eval("#{view_method_name}()") if eval("typeof #{view_method_name} == 'function'")
    view_action_method_name = $("body").data("view") + "_"+$("body").data("action")+"_onload"
    eval("#{view_action_method_name}()") if eval("typeof #{view_action_method_name} == 'function'")

users.js.coffee (กาแฟเฉพาะตัวควบคุมเช่นตัวควบคุม: ผู้ใช้การกระทำ: แผงควบคุม)

window.users_dashboard_onload = () ->
    alert("controller action called")
window.users_onload = () ->
    alert("controller called")

application.html.haml

%body{:data=>{:view=>controller.controller_name, :action=>controller.action_name}}

downvoting สิ่งนี้มีความซับซ้อนอย่างน่าขัน - ไม่ต้องพูดถึงที่ไม่ปลอดภัย (เนื่องจากeval) หาก HTML ของคุณถูกบุกรุกโดยเซิร์ฟเวอร์ที่ถอดรหัสหรือผู้ใช้ที่เป็นอันตราย
Marnen Laibow-Koser

-3

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

เนื่องจากเป็นการดีที่จะฝังโค้ด Javascript ไว้ใน HTML อย่างสมบูรณ์เพียงแค่สร้างภายใต้ไดเรกทอรี app / views shared.js และวางรหัสเฉพาะของหน้า / หน้าไว้ในmy_cool_partial.html.erb

<script type="text/javascript"> 
<!--
  var your_code_goes_here = 0;
  function etc() {
     ...
  }
-->
</script>

ดังนั้นจากที่ใดก็ตามที่คุณต้องการให้คุณทำ:

  = render :partial => 'shared.js/my_cool_partial'

และนั่นคือ k?


2
downvoting ไม่แนะนำให้เลือก JavaScript แบบอินไลน์ HTML ควรมีมาร์กอัปเท่านั้น JS และ CSS ควรแยกไฟล์ที่สามารถใช้ซ้ำได้
Marnen Laibow-Koser
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.