วิธีที่ดีที่สุดในการเพิ่ม JavaScript เฉพาะหน้าในแอพ Rails 3?


159

Rails 3 มี JavaScript ที่ไม่สร้างความรำคาญซึ่งเยี่ยมมาก

แต่ฉันสงสัยว่าวิธีที่ดีที่สุดคือการรวม JavaScript เพิ่มเติมสำหรับหน้าใดหน้าหนึ่ง

ตัวอย่างเช่นที่ฉันอาจทำก่อนหน้านี้:

<%= f.radio_button :rating, 'positive', :onclick => "$('some_div').show();" %>

ตอนนี้เราสามารถทำให้มันไม่เป็นการรบกวนกับสิ่งที่ชอบ

<%= f.radio_button :rating, 'positive' %>

# then in some other file
$('user_rating_positive').click(function() {
  $('some_div').show();
}

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



สำหรับผู้ที่ต้องการความเข้าใจที่เต็มรูปแบบของวิธีการทำงานนี้และสิ่งที่ดีที่สุดโปรดอ่านrailsapps.github.io/rails-javascript-include-external.html นี่คือเอกสารที่ดีที่สุดเท่าที่ฉันเคยเห็นในหัวข้อนี้ มันเป็นการอ่านที่ยอดเยี่ยมไม่เพียง แต่สำหรับ Rails เท่านั้น นี่คือเหตุผลที่ดีที่สุดที่จะทำสิ่งต่าง ๆ ในทางรถไฟ แน่นอนฉันจะใช้ Unholy Rails สำหรับคำถามในอนาคตของฉัน ว้าว.
DutGRIFF

2
@KateGregory ว่าเป็นรุ่นใหม่กว่า
Ciro Santilli 郝海东冠状病六四事件法轮功

คำตอบ:


153

สิ่งที่ฉันต้องการทำคือรวม Javascript ต่อการดูในcontent_for :headบล็อกและบล็อกนั้นyieldในเค้าโครงแอปพลิเคชันของคุณ ตัวอย่างเช่น

ถ้ามันค่อนข้างสั้นแล้ว:

<% content_for :head do %>
  <script type="text/javascript">
    $(function() {
      $('user_rating_positve').click(function() {
        $('some_div').show();
      }
    });
  </script>
<% end %>

หรือถ้านานกว่านั้น:

<% content_for :head do %>
  <script type="text/javascript">
    <%= render :partial => "my_view_javascript"
  </script>
<% end %>

จากนั้นในไฟล์เลย์เอาต์ของคุณ

<head>
  ...
  <%= yield :head %>
</head>

40
ทำไมไม่ใช้<%= javascript_include_tag "my_javascipt_file" %> ?
AJP

5
@AJP ฉันเดาว่ามันจะเอาชนะจุดประสงค์ของการวางท่อ
lulalala

2
@ lulalala แต่ไม่รหัสในคำตอบทำอย่างนั้น แต่ในแฟชั่น messier?
AJP

8
@AJP มันยุ่งกว่า แต่มีคำขอ http น้อยกว่าหนึ่งที่จะตอบได้มากกว่าคำตอบของคุณ
lulalala

4
ฉันชอบบทความนี้railsapps.github.com/rails-javascript-include-external.html
Ziggy

103

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

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

  • สินทรัพย์
    • javascripts
      • ผู้ดูแลระบบ
        • ... js
      • admin.js (รายการสำหรับกลุ่มผู้ดูแลระบบ)
      • application.js (รายการสำหรับกลุ่มส่วนกลางของแอป)
      • ทั่วโลก
        • ... js

ใน application.js ที่มีอยู่

//= require jquery
//= require jquery_ujs
//= require_tree ./global // requires all js files in global folder

ในไฟล์รายการ admin.js ใหม่

//= require_tree ./admin // requires all js files in admin folder

ตรวจสอบให้แน่ใจว่ามีการโหลด js รายการใหม่โดยแก้ไข config / production.rb

config.assets.precompile += %w( admin.js )

จากนั้นปรับเค้าโครงหน้าของคุณเพื่อให้คุณสามารถรวม js พิเศษบางอย่างสำหรับส่วนหัวของหน้า:

<%= content_for :header %>   

จากนั้นในมุมมองที่คุณต้องการรวมกลุ่ม js เฉพาะนี้ (รวมถึงกลุ่มแอปพลิเคชันทั่วไป) และ / หรือ js เฉพาะหน้าใด ๆ css และอื่น ๆ :

<% content_for :header do %>
  <%= javascript_include_tag 'admin' %>  
<% end %>

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


หากคุณเก็บรายการทั้งหมดของคุณไว้ในที่เดียวกันคุณสามารถบอกทางรถไฟให้คอมไพล์ทุกอย่างในโฟลเดอร์นั้นได้ ด้วยวิธีนี้คุณจะต้องแก้ไขการผลิตเพียงครั้งเดียวและอย่าติดตามสิ่งที่คุณเพิ่มเข้าไป
Undistraction

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

คี่ฉันได้รับ Sprockets :: FileNotFound ข้อผิดพลาดถ้าฉันใช้//= require_tree ./globalแต่ไม่ใช่ถ้าฉันใช้//= require_directory ./globalRails 3.2.12
qix

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

1
ฉันคิดว่าฉันเข้าใจ. การหลีกเลี่ยงแท็กสคริปต์เพิ่มเติมเป็นสิ่งสำคัญในการโหลดหน้าเว็บ
Ziggy

12

คำตอบเหล่านี้ช่วยฉันได้มาก! หากใครต้องการมากกว่านั้น ...

  1. คุณต้องใส่ javascripts ไว้ในรายการหากคุณต้องการคอมไพล์ล่วงหน้า อย่างไรก็ตามหากคุณต้องการไฟล์ javascript ทุกไฟล์จากapplication.js.coffeeนั้นไฟล์javacsripts ทั้งหมดจะถูกโหลดทุกครั้งที่คุณนำทางไปยังหน้าอื่น ๆ และวัตถุประสงค์ในการทำจาวาสคริปต์เฉพาะหน้าจะถูกกำจัด

ดังนั้นคุณต้องสร้างไฟล์รายการของคุณเอง (เช่นspeciifc.js) ที่จะต้องใช้ไฟล์จาวาสคริปต์เฉพาะสำหรับหน้าทั้งหมด นอกจากนี้แก้ไขrequire_treeจากapplication.js

app / สินทรัพย์ / javascripts / application.js

//= require jquery
//= require jquery_ujs
//= require_tree ./global

app / สินทรัพย์ / javascripts / specific.js

//= require_tree ./specific

จากนั้นในรายการenvironments/production.rbเพิ่มของคุณนี้ไปยังรายการที่คอมไพล์แล้วด้วยตัวเลือกการกำหนดค่า

config.assets.precompile += %w( specific.js )

ทำ! ทั้งหมดร่วมกัน javascripts ที่ควรจะโหลดจะถูกวางไว้ในapp/assets/javascripts/globalโฟลเดอร์และ javascripts หน้า spcific app/assets/javascripts/specificใน คุณสามารถเรียกจาวาสคริปต์เฉพาะหน้าได้จากมุมมองที่ต้องการ

<%= javascript_include_tag "specific/whatever.js" %> //.js เป็นทางเลือก

เพียงพอแล้ว แต่ฉันก็อยากจะใช้javascript_include_tag params[:controller]เช่นกัน เมื่อคุณสร้างตัวควบคุมไฟล์ coffeescript ที่เกี่ยวข้องจะถูกสร้างขึ้นapp/assets/javascriptsเช่นเดียวกับคนอื่น ๆ ที่กล่าวถึง มีตัวควบคุมเฉพาะอย่างแท้จริงจาวาสคริปต์ซึ่งโหลดเมื่อผู้ใช้มาถึงมุมมองตัวควบคุมที่ระบุเท่านั้น

ดังนั้นฉันจึงสร้างรายการอื่น controller-specific.js

app / สินทรัพย์ / javascripts / ควบคุม-specific.js

//= require_directory .

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

config.assets.precompile += %w( specific.js controller-specific.js )


ขอบคุณมากสำหรับคำตอบอย่างละเอียด ฉันควรใส่บรรทัดนี้ไว้ตรง javascript_include_tag params[:controller]ไหน ปัจจุบันของฉัน application.html.erb มีบรรทัดjavascript_include_tag 'application'นี้ ฉันควรแทนที่ด้วยบรรทัดอื่นหรือไม่
simha

1
นอกจากนี้ฉันควรใส่บรรทัดนี้<%= javascript_include_tag "specific/whatever.js" %>ในcontent_for :headerบล็อกหรือไม่
simha

1
config.assets.precompileมันแปลกที่ฉันว่าคุณต้องไปยุ่งกับ ไม่ใช่ทุกอย่างที่อยู่ในการคอมapp/assets/javascripts/*.jsไพล์ล่วงหน้าโดยอัตโนมัติใช่ไหม
AlexChaffee

@AlexChaffee เฉพาะไฟล์ที่มีอยู่โดยอัตโนมัติและapplication.css application.jsคนอื่น ๆ ได้ที่จะรวมทั้งในไฟล์อื่น ๆ config.assets.precompileหรือระบุไว้ใช้ อ่านเพิ่มเติมได้ที่นี่
Sung Cho

ประกาศรายการที่ถูกย้าย ฉันใช้ราง 4.2.0 และพบความคิดเห็นนี้ในไฟล์ production.rb: # config.assets.precompileและconfig.assets.versionย้ายไปยัง config / initializers / assets.rb
curt

11

ฉันชอบสิ่งต่อไปนี้ ...

ในไฟล์ application_helper.rb ของคุณ

def include_javascript (file)
    s = " <script type=\"text/javascript\">" + render(:file => file) + "</script>"
    content_for(:head, raw(s))
end

จากนั้นในมุมมองเฉพาะของคุณ (แอพ / อ่าน / หนังสือ / index.html.erb ในตัวอย่างนี้)

<% include_javascript 'books/index.js' %>

... ดูเหมือนว่าจะทำงานให้ฉัน


9

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

<%= javascript_include_tag "my_javascipt_file" %>

หมายเหตุ: ต้องมีการร้องขอ http อีกหนึ่งรายการต่อแท็กรวมกว่าคำตอบที่ใช้ content_for :head


javascript_include_tagนั่นคือสิ่งที่ฉันกำลังมองหาไชโย AJP
Tom McKenzie

คุณใส่ "my_javascipt_file" ไว้ที่ไหน ในสินทรัพย์ / javascripts? แต่ถ้าเป็นเช่นนั้นจะไม่ได้รับโดยอัตโนมัติด้วย//= require .ใน application.js?
qix

@Linus ใช่แล้ว//= require .จะนำสคริปต์นั้นไปที่หน้าใด ๆ ในไซต์ของคุณดังนั้นคุณต้องทำอะไรบางอย่างเช่น Kenny Grant (ใช้//= require_tree ./global) หรือแนะนำ bjg
AJP

1
นี่เป็นวิธีที่ง่ายที่สุดสำหรับฉันฉันเปลี่ยน//= require_tree .เป็น//= require_directory .ใน application.js จากนั้นสร้างไดเรกทอรีย่อยใน asset \ javascripts โปรดทราบว่าคุณจะต้องรวมไดเรกทอรีใหม่ใน config \ initializers \ assets.rb เพื่อคอมไพล์ js ของคุณล่วงหน้าโดยเพิ่มบรรทัด:Rails.application.config.assets.precompile += %w( new_dir/js_file.js )
Jonesy


3

ความเข้าใจของฉันคือว่าไปป์ไลน์ของเนื้อหานั้นมีวัตถุประสงค์เพื่อลดเวลาในการโหลดหน้าเว็บโดยการรวม js ทั้งหมดของคุณเข้าด้วยกันเป็นไฟล์เดียว (ลดขนาด) แม้ว่าสิ่งนี้อาจดูน่ารังเกียจบนพื้นผิว แต่จริงๆแล้วเป็นคุณลักษณะที่มีอยู่แล้วในภาษายอดนิยมเช่น C และ Ruby สิ่งต่างๆเช่นแท็ก "รวม" มีไว้เพื่อป้องกันการรวมไฟล์หลายไฟล์และเพื่อช่วยโปรแกรมเมอร์จัดระเบียบรหัสของพวกเขา เมื่อคุณเขียนและคอมไพล์โปรแกรมใน C โค้ดนั้นจะมีอยู่ในทุกส่วนของโปรแกรมที่กำลังทำงานของคุณ แต่เมธอดจะโหลดลงในหน่วยความจำเท่านั้นเมื่อใช้โค้ดนั้น ในความหมายโปรแกรมที่คอมไพล์ไม่ได้รวมสิ่งใด ๆ ที่จะรับประกันว่ารหัสนั้นเป็นแบบแยกส่วน เราสร้างโค้ดแบบแยกส่วนโดยการเขียนโปรแกรมของเราด้วยวิธีนี้และระบบปฏิบัติการจะโหลดหน่วยความจำเฉพาะวัตถุและวิธีการที่เราต้องการสำหรับพื้นที่ที่กำหนด มีแม้กระทั่งสิ่งเช่น "รวมวิธีเฉพาะ" หรือไม่ หากแอพพลิเคชั่น Rails ของคุณนั้นเงียบสงบนี่เป็นสิ่งที่คุณต้องการ

หากคุณเขียนจาวาสคริปต์ของคุณเพื่อเพิ่มลักษณะการทำงานขององค์ประกอบ HTML บนหน้าเว็บฟังก์ชั่นเหล่านั้นคือ 'หน้าเฉพาะ' โดยการออกแบบ หากมีรหัสที่ซับซ้อนบางอย่างที่คุณเขียนในลักษณะที่มันจะดำเนินการโดยไม่คำนึงถึงบริบทของมันอาจพิจารณาผูกพันรหัสนั้นกับองค์ประกอบ HTML ต่อไป (คุณสามารถใช้แท็กร่างกายตามที่อธิบายไว้ในวิธีการGarber-Irish ) หากฟังก์ชั่นทำงานตามเงื่อนไขประสิทธิภาพอาจมีขนาดเล็กกว่าแท็กสคริปต์พิเศษเหล่านั้นทั้งหมด

ผมคิดว่าการใช้Palomaอัญมณีที่อธิบายไว้ในโครงการรางปพลิเคชัน จากนั้นคุณสามารถสร้างหน้าเฉพาะจาวาสคริปต์ของคุณโดยรวมฟังก์ชั่นเฉพาะหน้าในการโทรกลับ Paloma:

Paloma.callbacks['users']['new'] = function(params){
    // This will only run after executing users/new action
    alert('Hello New Sexy User');
}; 

คุณใช้รางดังนั้นฉันรู้ว่าคุณรักอัญมณี :)


3

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

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

ขออภัยด้วยเหตุผลใดก็ตามที่ Rails devs ตัดสินใจว่าโดยค่าเริ่มต้นทุกหน้าจะโหลดไฟล์ JS ทุกไฟล์ที่อยู่ในไดเรกทอรีสินทรัพย์ของคุณ ทำไมพวกเขาตัดสินใจทำเช่นนี้แทนที่จะเปิดใช้งาน "ตัวควบคุมจาวาสคริปต์เฉพาะ" โดยค่าเริ่มต้นฉันจะไม่มีทางรู้ สิ่งนี้ทำผ่านไฟล์ application.js ซึ่งมีบรรทัดของรหัสต่อไปนี้เป็นค่าเริ่มต้น:

//= require_tree .

นี้เป็นที่รู้จักในฐานะผู้สั่ง มันเป็นสิ่งที่เฟืองใช้ในการโหลดไฟล์ JS ทุกไฟล์ในไดเรกทอรีสินทรัพย์ / javascripts โดยค่าเริ่มต้นเฟืองจะโหลด application.js และ application.css โดยอัตโนมัติและคำสั่ง require_tree จะโหลดไฟล์ JS และ Coffee ทุกไฟล์ในไดเรกทอรีที่เกี่ยวข้อง

หมายเหตุ:เมื่อคุณนั่งร้าน (หากคุณไม่ได้นั่งร้านตอนนี้เป็นเวลาที่ดีในการเริ่มต้น) Rails จะสร้างไฟล์กาแฟให้คุณโดยอัตโนมัติสำหรับตัวควบคุมนั่งร้านนั้น หากคุณต้องการให้มันสร้างไฟล์JS มาตรฐานแทนที่จะเป็นไฟล์กาแฟให้ลบgem gemที่เปิดใช้งานโดยค่าเริ่มต้นในGemfileของคุณและ scaffold ของคุณจะสร้างไฟล์ JS แทน

ตกลงดังนั้นขั้นตอนแรกในการเปิดใช้งาน "ตัวควบคุมจาวาสคริปต์ที่เฉพาะเจาะจง" คือการลบรหัส require_tree จากไฟล์ application.js ของคุณหรือเปลี่ยนเป็นโฟลเดอร์ภายในไดเรกทอรีสินทรัพย์ / javascripts ของคุณหากคุณยังต้องการไฟล์ JS ทั่วโลก IE:

//= require_tree ./global

ขั้นตอนที่ 2:เข้าไปที่ไฟล์ config / initializers / assets.rb ของคุณและเพิ่มรายการต่อไปนี้:

%w( controllerone controllertwo controllerthree ).each do |controller|
  Rails.application.config.assets.precompile += ["#{controller}.js", "#{controller}.css"]
end

ใส่ชื่อคอนโทรลเลอร์ที่คุณต้องการ

ขั้นตอนที่ 3:แทนที่ javascript_include_tag ในไฟล์ application.html.erb ของคุณด้วยสิ่งนี้ (หมายเหตุส่วน params [: controller]:

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

รีสตาร์ทเซิร์ฟเวอร์และวิโอล่าของคุณ! ไฟล์ JS ที่สร้างโดยนั่งร้านของคุณจะโหลดตอนนี้เมื่อมีการเรียกตัวควบคุมนั้นเท่านั้น

ต้องการโหลดไฟล์ JS เฉพาะใน ACTION เฉพาะในคอนโทรลเลอร์ของคุณ IE / บทความ / ใหม่หรือไม่ ทำสิ่งนี้แทน:

application.html.erb :

<%= javascript_include_tag "#{controller_name}/#{action_name}" if AppName::Application.assets.find_asset("#{controller_name}/#{action_name}") %>

config / initializers / assets.rb :

config.assets.precompile += %w(*/*)

จากนั้นเพิ่มโฟลเดอร์ใหม่ที่มีชื่อเดียวกับที่คุณควบคุมในโฟลเดอร์ทรัพย์สิน / javascripts ของคุณและวางไฟล์ js ของคุณด้วยชื่อเดียวกับการกระทำของคุณ จากนั้นจะโหลดในการดำเนินการเฉพาะนั้น


1

ตกลงดังนั้นนี่อาจเป็นงานที่แย่ที่สุด แต่ฉันสร้างวิธีควบคุมที่เพิ่งแสดงไฟล์. js

ตัวควบคุม

def get_script
   render :file => 'app/assessts/javascripts/' + params[:name] + '.js'
end
def get_page
   @script = '/' + params[:script_name] + '.js?body=1'
   render page
end

ดู

%script{:src => @script, :type => "text/javascript"}

ถ้าด้วยเหตุผลบางอย่างเราไม่ต้องการทำสิ่งนี้โปรดแจ้งให้เราทราบ


1

วิธีที่ต้องการเพิ่ม JS อยู่ในส่วนท้ายดังนั้นคุณสามารถทำสิ่งนี้ได้:

show.html.erb:

<% content_for :footer_js do %>
   This content will show up in the footer section
<% end %>

รูปแบบ / application.html.erb

<%= yield :footer_js %>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.