Cara terbaik untuk menambahkan JavaScript khusus halaman dalam aplikasi Rails 3?

159

Rails 3 memiliki beberapa JavaScript yang tidak mencolok yang cukup keren.

Tapi saya bertanya-tanya apa cara terbaik untuk memasukkan JavaScript tambahan untuk halaman tertentu.

Misalnya, di mana saya sebelumnya mungkin telah melakukan:

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

Kita sekarang dapat membuatnya tidak mengganggu dengan sesuatu seperti

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

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

Jadi saya kira pertanyaan saya adalah di mana / bagaimana cara memasukkan JavaScript itu? Saya tidak ingin mengisi application.jsfile karena JavaScript ini hanya berlaku untuk tampilan yang satu ini. Haruskah saya menyertakan file JavaScript khusus untuk setiap halaman, atau menempelnya dalam variabel instan yang dicari oleh header?

Brian Armstrong
sumber
Bagi mereka yang menginginkan pemahaman penuh tentang cara kerjanya dan apa yang terbaik, silakan baca railsapps.github.io/rails-javascript-include-external.html . Sejauh ini, ini adalah dokumentasi terbaik yang pernah saya lihat tentang topik ini. Ini adalah bacaan yang bagus tidak hanya untuk Rails tetapi untuk siapa pun yang berurusan di web dev. Inilah sebabnya mengapa yang terbaik adalah melakukan hal-hal dengan cara rel. Saya pasti akan menggunakan Unholy Rails untuk pertanyaan saya di masa depan. WOW.
DutGRIFF
2
@KateGregory yang lebih baru.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Jawaban:

153

Yang ingin saya lakukan adalah memasukkan Javascript per-view dalam sebuah content_for :headblok dan kemudian yieldke blok itu dalam tata letak aplikasi Anda. Sebagai contoh

Jika cukup pendek maka:

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

atau, jika lebih lama, maka:

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

Lalu, di file tata letak Anda

<head>
  ...
  <%= yield :head %>
</head>
bjg
sumber
40
Kenapa tidak menggunakan <%= javascript_include_tag "my_javascipt_file" %> ?
AJP
5
@ AJP Saya kira itu mengalahkan tujuan pipa aset
lulalala
2
@ Lulalala tetapi bukankah kode dalam jawaban tetap melakukannya tetapi dengan cara yang berantakan?
AJP
8
@ AJP itu berantakan, tetapi memiliki satu permintaan http kurang untuk membuat daripada jawaban Anda.
lulalala
103

Jika Anda ingin memasukkan javascript hanya pada satu halaman, Anda dapat memasukkannya di halaman inline tentu saja, namun jika Anda ingin mengelompokkan javascript Anda dan mengambil keuntungan dari pipeline aset, js yang diperkecil, dll., Dimungkinkan untuk melakukannya dan memiliki tambahan Aset js yang digabungkan dan hanya dimuat pada halaman tertentu dengan membagi js Anda menjadi grup yang hanya berlaku di bagian pengontrol / tampilan / tertentu dari situs.

Pindahkan aset js Anda ke folder, dengan file manifes terpisah untuk masing-masing, jadi jika Anda memiliki pustaka admin js yang hanya digunakan di backend, Anda dapat melakukan ini:

  • aktiva
    • skrip javascript
      • admin
        • ... js
      • admin.js (manifes untuk grup admin)
      • application.js (manifes untuk grup global aplikasi)
      • global
        • ... js

di application.js yang ada

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

dalam file manifes admin.js baru

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

Pastikan manifes js baru ini dimuat dengan mengedit config / production.rb

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

Kemudian sesuaikan tata letak halaman Anda sehingga Anda dapat memasukkan beberapa js tambahan untuk kepala halaman:

<%= content_for :header %>   

Kemudian dalam tampilan di mana Anda ingin memasukkan grup js spesifik ini (serta grup aplikasi normal) dan / atau js, css dll:

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

Anda tentu saja dapat melakukan hal yang sama dengan css dan mengelompokkannya dengan cara yang sama untuk menerapkan hanya pada area tertentu dari situs.

Kenny Grant
sumber
Jika Anda menyimpan semua manifes di tempat yang sama, Anda dapat memberi tahu rail untuk mengkompilasi semua yang ada di folder itu. Dengan begitu, Anda hanya perlu mengedit production.rb sekali dan tidak melacak apa yang telah Anda tambahkan ke dalamnya.
Undistraction
Tidak tahu Anda bisa melakukan itu - sehingga Anda dapat memiliki folder 'manifes' yang berisi manifes Anda, serta masing-masing grup js? Saya mungkin mencoba ini. Saya berharap mereka memiliki pengaturan yang sedikit lebih waras secara default karena tampaknya mereka menganggap Anda hanya akan menggumpalkan semua js menjadi satu file besar yang diimpor di mana-mana.
Kenny Grant
aneh, saya mendapatkan kesalahan Sprockets :: FileNotFound jika saya gunakan //= require_tree ./global, tetapi tidak jika saya //= require_directory ./globalmenggunakan Rails 3.2.12.
qix
2
Sepertinya Anda akan mendapatkan banyak tag skrip. Saya pikir tujuan dengan pipeline aset adalah memiliki hanya satu tag skrip? Saya hanya akan menulis javascripts sehingga mereka spesifik halaman.
Ziggy
1
Saya rasa saya mengerti. Menghindari tag skrip tambahan cukup penting untuk memuat waktu halaman.
Ziggy
12

Jawaban-jawaban ini membantu saya satu ton! Jika ada yang ingin lebih ...

  1. Anda perlu memasukkan javascripts ke manifes jika Anda menginginkannya dikompilasi. Namun, jika Anda memerlukan setiap file javascript dari application.js.coffeesemua javacsripts akan dimuat setiap kali Anda menavigasi ke halaman yang berbeda, dan tujuan melakukan javascripts spesifik halaman akan dikalahkan.

Oleh karena itu, Anda perlu membuat file manifes Anda sendiri (mis. speciifc.js) Yang akan membutuhkan semua file javascript khusus halaman. Juga, modifikasi require_treedariapplication.js

app / aset / javascripts / application.js

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

app / assets / javascripts / specific.js

//= require_tree ./specific

Kemudian di environments/production.rbtambahkan manifes ini ke daftar yang dikompilasi dengan opsi konfigurasi,

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

Selesai! Semua javascripts bersama yang harus selalu dimuat akan ditempatkan di app/assets/javascripts/globalfolder, dan javascripts halaman-spcific di app/assets/javascripts/specific. Anda dapat memanggil javascripts khusus halaman dari tampilan seperti

<%= javascript_include_tag "specific/whatever.js" %> //.js adalah opsional.

Ini sudah cukup, tetapi saya ingin memanfaatkannya javascript_include_tag params[:controller]juga. Saat Anda membuat pengontrol, file naskah kopi terkait dibuat app/assets/javascriptsseperti orang lain yang disebutkan. Ada benar-benar javascript skrip khusus , yang dimuat hanya ketika pengguna mencapai tampilan kontroler tertentu.

Jadi saya membuat manifes lain controller-specific.js

app / assets / javascripts / controller-specific.js

//= require_directory .

Ini akan mencakup semua skrip kopi yang dihasilkan secara otomatis yang terkait dengan pengontrol. Anda juga perlu menambahkannya ke daftar yang telah dikompilasi.

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

Maximus S
sumber
Terima kasih banyak untuk jawaban terperinci. Di mana saya harus meletakkan baris ini javascript_include_tag params[:controller]. Saat ini application.html.erb saya memiliki baris ini javascript_include_tag 'application'. Haruskah saya mengganti ini dengan saluran lain?
simha
1
Juga, haruskah saya meletakkan baris ini <%= javascript_include_tag "specific/whatever.js" %>di content_for :headerblok?
simha
1
Bagi saya aneh bahwa Anda perlu mengacaukannya config.assets.precompile. Bukankah semua yang ada di app/assets/javascripts/*.jspra-kompilasi secara otomatis?
AlexChaffee
@AlexChaffee Hanya file yang tersedia secara otomatis adalah application.cssdan application.js. Yang lain harus dimasukkan dalam file lain, atau terdaftar menggunakan config.assets.precompile. Baca lebih lanjut di sini
Sung Cho
Deklarasi manifes telah dipindahkan. Saya menjalankan rail 4.2.0. dan menemukan komentar ini dalam file production.rb: # config.assets.precompiledan config.assets.versiontelah pindah ke config / initializers / assets.rb
singkat
11

Saya lebih suka yang berikut ...

Dalam file application_helper.rb Anda

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

dan kemudian dalam tampilan khusus Anda (app / views / books / index.html.erb dalam contoh ini)

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

... sepertinya bekerja untukku.

cailinanne
sumber
9

Jika Anda tidak ingin menggunakan pipa aset atau pekerjaan kompleks untuk mendapatkan javascript khusus halaman yang diperlukan (saya bersimpati), cara paling sederhana dan paling kuat, yang mencapai hal yang sama dengan jawaban di atas tetapi dengan kode lebih sedikit hanya untuk menggunakan:

<%= javascript_include_tag "my_javascipt_file" %>

Catatan: ini memang membutuhkan satu lagi permintaan http per tag sertakan daripada jawaban yang digunakan content_for :head

AJP
sumber
javascript_include_tagpersis apa yang saya cari, sorak-sorai AJP
Tom McKenzie
di mana Anda meletakkan "my_javascipt_file"? Dalam aset / javascripts? Tetapi jika demikian, bukankah itu akan diambil secara otomatis dengan //= require .di application.js?
qix
@Linus ya, //= require .akan membawa skrip itu ke halaman mana pun di situs Anda sehingga Anda harus melakukan sesuatu seperti Kenny Grant (gunakan //= require_tree ./global) atau bjg yang disarankan.
AJP
1
Sejauh ini, ini adalah metode termudah bagi saya, saya ubah //= require_tree .ke //= require_directory .dalam application.js dan kemudian membuat sub-direktori dalam asset \ javascripts. Perhatikan bahwa Anda harus memasukkan direktori baru di config \ initializers \ assets.rb untuk mengkompilasi js Anda dengan menambahkan baris:Rails.application.config.assets.precompile += %w( new_dir/js_file.js )
Jonesy
7

Lihatlah permata pluggable_js . Anda mungkin menemukan solusi ini lebih mudah digunakan.

peresleguine
sumber
3

Pemahaman saya adalah bahwa pipa aset dimaksudkan untuk mengurangi waktu buka halaman dengan menggabungkan semua js Anda menjadi satu file (diperkecil). Meskipun ini mungkin tampak menjijikkan di permukaan, itu sebenarnya adalah fitur yang sudah ada dalam bahasa populer seperti C dan Ruby. Hal-hal seperti tag "sertakan" dimaksudkan untuk mencegah dimasukkannya banyak file, dan untuk membantu programmer mengatur kode mereka. Ketika Anda menulis dan mengkompilasi program dalam C, semua kode itu ada di setiap bagian dari program Anda yang sedang berjalan, tetapi metode hanya dimuat ke dalam memori ketika kode itu sedang digunakan. Dalam arti tertentu, program yang dikompilasi tidak termasuk apa pun untuk menjamin bahwa kode tersebut modular dengan baik. Kami membuat kode modular dengan menulis program kami seperti itu, dan sistem operasi hanya memuat ke dalam memori objek dan metode yang kami butuhkan untuk lokasi tertentu. Apakah ada yang namanya "penyertaan khusus metode"? Jika aplikasi rel Anda tenang, ini pada dasarnya adalah apa yang Anda minta.

Jika Anda menulis javascript Anda sehingga menambah perilaku elemen HTML pada halaman, maka fungsi-fungsi itu 'spesifik-halaman' menurut desain. Jika ada beberapa kode rumit yang Anda tulis sedemikian rupa sehingga akan dieksekusi terlepas dari konteksnya, mungkin pertimbangkan untuk mengikat kode itu ke elemen html (Anda dapat menggunakan tag tubuh, seperti yang dijelaskan dalam metode Garber-Irlandia ). Jika suatu fungsi dieksekusi secara kondisional, kinerja mungkin akan lebih kecil dari semua tag skrip tambahan itu.

Saya berpikir untuk menggunakan permata paloma , seperti yang dijelaskan dalam proyek aplikasi rel . Kemudian Anda dapat membuat javascript khusus halaman Anda dengan memasukkan fungsi spesifik halaman dalam paloma callback:

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

Anda menggunakan rel, jadi saya tahu Anda suka permata :)

Ziggy
sumber
3

Anda tidak boleh memuat file JS atau CSS Anda di luar pipa aset karena Anda kehilangan fitur penting yang membuat Rails begitu hebat. Dan Anda tidak perlu permata lain. Saya percaya menggunakan permata sesedikit mungkin, dan menggunakan permata tidak perlu di sini.

Apa yang Anda inginkan dikenal sebagai "Kontroler Javascript Khusus" ("Aksi Javascript Khusus termasuk di bagian bawah). Ini memungkinkan Anda untuk memuat file JavaScript spesifik untuk CONTROLLER tertentu. Mencoba menghubungkan Javascript Anda ke Tampilan adalah jenis .. .mundur dan tidak mengikuti pola desain MVC. Anda ingin mengaitkannya dengan Pengontrol Anda atau tindakan di dalam Pengontrol Anda.

Sayangnya, untuk alasan apa pun, Rails devs memutuskan bahwa secara default, setiap halaman akan memuat setiap file JS yang terletak di direktori aset Anda. Mengapa mereka memutuskan untuk melakukan ini alih-alih mengaktifkan "Controller Specific Javascript" secara default saya tidak akan pernah tahu. Ini dilakukan melalui file application.js, yang termasuk baris kode berikut secara default:

//= require_tree .

Ini dikenal sebagai arahan . Itulah yang digunakan sprocket untuk memuat setiap file JS di direktori assets / javascripts. Secara default, sprocket secara otomatis memuat application.js dan application.css, dan direktif_tree memuat setiap file JS dan Coffee di masing-masing direktori.

CATATAN: Ketika Anda perancah (jika Anda tidak perancah, sekarang adalah waktu yang tepat untuk memulai), Rails secara otomatis menghasilkan file kopi untuk Anda, untuk pengontrol perancah itu. Jika Anda menginginkannya untuk menghasilkan file JS standar alih-alih file kopi , maka hapus permata kopi yang diaktifkan secara default di Gemfile Anda , dan perancah Anda akan membuat file JS sebagai gantinya.

Oke, jadi langkah pertama untuk mengaktifkan "Kontroler Javascript Khusus" adalah menghapus kode require_tree dari file application.js Anda, ATAU ubah ke folder di dalam direktori aset / javascripts Anda jika Anda masih memerlukan file JS global. YAITU:

//= require_tree ./global

Langkah 2: Buka file config / initializers / assets.rb Anda, dan tambahkan yang berikut ini:

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

Masukkan nama Controller yang Anda inginkan.

Langkah 3: Ganti file javascript_include_tag di file application.html.erb Anda dengan ini (perhatikan bagian params [: controller]:

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

Mulai ulang server dan biola Anda! File JS yang dihasilkan dengan perancah Anda sekarang hanya akan memuat ketika kontroler itu dipanggil.

Perlu memuat file JS tertentu pada AKSI spesifik di controller Anda , IE / artikel / baru ? Lakukan ini sebagai gantinya:

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(*/*)

Kemudian tambahkan folder baru dengan nama yang sama seperti Anda controller di folder aset / javascripts Anda dan letakkan file js Anda dengan nama yang sama dengan tindakan Anda di dalamnya. Ini kemudian akan memuatnya pada tindakan spesifik itu.

Erick Maynard
sumber
1

Ok jadi mungkin ini seperti pekerjaan terburuk yang pernah ada tetapi saya membuat metode pengontrol yang baru saja membuat file .js

Pengendali

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

Melihat

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

jika karena alasan tertentu kami tidak ingin melakukan ini maka beri tahu saya.

Tagihan
sumber
1

Cara yang disukai untuk menambahkan JS ada di footer, jadi Anda bisa melakukan ini:

show.html.erb:

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

tata letak / application.html.erb

<%= yield :footer_js %>
Syed
sumber