Cách tốt nhất để thêm JavaScript cụ thể của trang trong ứng dụng Rails 3?


159

Rails 3 có một số JavaScript không phô trương, khá tuyệt.

Nhưng tôi đã tự hỏi cách tốt nhất là bao gồm JavaScript bổ sung cho một trang cụ thể.

Ví dụ, nơi tôi có thể đã thực hiện trước đây:

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

Bây giờ chúng ta có thể làm cho nó không phô trương với một cái gì đó như

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

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

Vì vậy, tôi đoán câu hỏi của tôi là ở đâu / làm thế nào để bao gồm JavaScript đó? Tôi không muốn điền vào application.jstệp vì JavaScript này chỉ áp dụng cho chế độ xem này. Tôi có nên bao gồm một tệp JavaScript tùy chỉnh cho mỗi trang bằng cách nào đó hoặc dán nó vào một biến đối tượng mà tiêu đề tìm kiếm không?



Đối với những người muốn có một sự hiểu biết đầy đủ về cách thức hoạt động của nó và những gì tốt nhất xin vui lòng đọc railsapps.github.io/rails-javascript-include-external.html . Đây là tài liệu tốt nhất tôi đã thấy về chủ đề này. Đây là một bài đọc tuyệt vời không chỉ cho Rails mà cho bất kỳ ai kinh doanh web dev. Đây là lý do tại sao tốt nhất là làm mọi thứ theo cách đường ray. Tôi chắc chắn sẽ sử dụng Unholy Rails cho các câu hỏi trong tương lai của tôi. Ôi.
DutGRIFF

2
@KateGregory rằng một cái mới hơn.
Ciro Santilli 郝海东 冠状 病 事件

Câu trả lời:


153

Những gì tôi muốn làm là bao gồm Javascript cho mỗi lượt xem trong một content_for :headkhối và sau đó yieldđến khối đó trong bố cục ứng dụng của bạn. Ví dụ

Nếu nó khá ngắn thì:

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

hoặc, nếu lâu hơn, thì:

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

Sau đó, trong tập tin bố trí của bạn

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

40
Tại sao không sử dụng <%= javascript_include_tag "my_javascipt_file" %> ?
AJP

5
@AJP Tôi đoán sau đó nó đánh bại mục đích của đường ống tài sản
lulalala

2
@lulalala nhưng không phải mã trong câu trả lời sẽ làm điều đó nhưng theo cách lộn xộn hơn?
AJP

8
@AJP thì rắc rối hơn, nhưng nó có ít yêu cầu http hơn là câu trả lời của bạn.
lulalala


103

Nếu bạn muốn bao gồm javascript chỉ trên một trang, bạn có thể đưa nó vào nội tuyến của trang, tuy nhiên nếu bạn muốn nhóm javascript của mình và tận dụng đường dẫn tài sản, js rút gọn, v.v., bạn có thể làm như vậy và có thêm tài sản js được kết hợp và chỉ được tải trên các trang cụ thể bằng cách chia js của bạn thành các nhóm chỉ áp dụng trong các bộ điều khiển / lượt xem / phần nhất định của trang web.

Di chuyển js của bạn trong tài sản vào các thư mục, với một tệp kê khai riêng cho từng tệp, vì vậy nếu bạn có thư viện js quản trị viên chỉ được sử dụng trên phụ trợ, bạn có thể thực hiện việc này:

  • tài sản
    • javascripts
      • quản trị viên
        • ... js
      • admin.js (tệp kê khai cho nhóm quản trị viên)
      • application.js (bảng kê khai cho nhóm toàn cầu ứng dụng)
      • toàn cầu
        • ... js

trong application.js hiện có

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

trong tệp kê khai admin.js mới

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

Hãy chắc chắn rằng bảng kê khai js mới này được tải bằng cách chỉnh sửa cấu hình / sản xuất.rb

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

Sau đó điều chỉnh bố cục trang của bạn để bạn có thể bao gồm một số js bổ sung cho đầu trang:

<%= content_for :header %>   

Sau đó, trong các chế độ xem bạn muốn bao gồm nhóm js cụ thể này (cũng như nhóm ứng dụng thông thường) và / hoặc bất kỳ js cụ thể nào của trang, css, v.v.

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

Tất nhiên bạn có thể làm điều tương tự với css và nhóm nó theo cách tương tự để chỉ áp dụng cho các khu vực nhất định của trang web.


Nếu bạn giữ tất cả các bảng kê khai của mình ở cùng một nơi, bạn có thể nói đường ray để biên dịch trước mọi thứ trong thư mục đó. Bằng cách đó, bạn chỉ cần chỉnh sửa sản xuất một lần và không theo dõi những gì bạn đã thêm vào nó.
Undistraction

Bạn không biết bạn có thể làm điều đó - vì vậy bạn có thể có một thư mục 'bảng kê khai' chứa các bảng kê khai của bạn, cũng như các nhóm js riêng lẻ? Tôi có thể thử nó. Tôi ước gì họ có một thiết lập lành mạnh hơn một chút theo mặc định vì có vẻ như họ cho rằng bạn sẽ chỉ toàn bộ js vào một tệp lớn được nhập ở khắp mọi nơi.
Kenny Grant

lẻ, tôi gặp lỗi Sprockets :: FileNotFound nếu tôi sử dụng //= require_tree ./global, nhưng không phải nếu tôi sử //= require_directory ./globaldụng Rails 3.2.12.
qix

2
Có vẻ như bạn sẽ kết thúc với nhiều thẻ script. Tôi nghĩ mục tiêu với đường ống tài sản là chỉ có một thẻ script? Tôi sẽ chỉ viết các javascripts để chúng là trang cụ thể.
Ziggy

1
Tôi nghĩ rằng tôi hiểu. Tuy nhiên, việc tránh các thẻ script bổ sung khá quan trọng đối với thời gian tải trang.
Ziggy

12

Những câu trả lời đã giúp tôi rất nhiều! Nếu ai muốn thêm một chút ...

  1. Bạn cần đặt javascripts vào bảng kê khai nếu bạn muốn chúng được biên dịch trước. Tuy nhiên, nếu bạn yêu cầu mọi tệp javascript từ application.js.coffeeđó thì tất cả các javacs script sẽ được tải mỗi khi bạn điều hướng đến một trang khác và mục đích thực hiện các javascripts dành riêng cho trang sẽ bị đánh bại.

Do đó, bạn cần tạo tệp kê khai của riêng mình (ví dụ speciifc.js) sẽ yêu cầu tất cả các tệp javascript dành riêng cho trang. Ngoài ra, sửa đổi require_treetừapplication.js

ứng dụng / tài sản / javascripts / application.js

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

ứng dụng / tài sản / javascripts / cụ thể.js

//= require_tree ./specific

Sau đó, bạn environments/production.rbthêm tệp kê khai này vào danh sách được biên dịch trước với tùy chọn cấu hình,

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

Làm xong! Tất cả các javascripts được chia sẻ sẽ luôn được tải sẽ được đặt trong app/assets/javascripts/globalthư mục và các javascripts trang-spcific trong app/assets/javascripts/specific. Bạn chỉ có thể gọi các javascripts dành riêng cho trang từ chế độ xem như

<%= javascript_include_tag "specific/whatever.js" %> //.js là tùy chọn.

Điều này là đủ, nhưng tôi muốn sử dụng javascript_include_tag params[:controller]quá. Khi bạn tạo bộ điều khiển, một tệp coffeescript được liên kết sẽ được tạo app/assets/javascriptsgiống như những người khác được đề cập. Có các javascripts dành riêng cho bộ điều khiển , chỉ được tải khi người dùng đạt đến chế độ xem bộ điều khiển cụ thể.

Vì vậy, tôi đã tạo ra một bảng kê khai khác controller-specific.js

ứng dụng / tài sản / javascripts / control-own.js

//= require_directory .

Điều này sẽ bao gồm tất cả các loại cà phê được tạo tự động liên quan đến bộ điều khiển. Ngoài ra, bạn cần thêm nó vào danh sách được biên dịch trước.

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


Cảm ơn rất nhiều cho câu trả lời chi tiết. Tôi nên đặt dòng này ở đâu javascript_include_tag params[:controller]. Hiện tại application.html.erb của tôi có dòng này javascript_include_tag 'application'. Tôi có nên thay thế bằng dòng khác?
simha

1
Ngoài ra, tôi có nên đặt dòng này <%= javascript_include_tag "specific/whatever.js" %>trong một content_for :headerkhối?
simha

1
Thật kỳ lạ với tôi rằng bạn cần phải gây rối config.assets.precompile. Không phải mọi thứ trong app/assets/javascripts/*.jstiền biên dịch tự động sao?
AlexChaffee

@AlexChaffee Chỉ các tệp có sẵn tự động là application.cssapplication.js. Những người khác phải được bao gồm trong các tập tin khác, hoặc được liệt kê bằng cách sử dụng config.assets.precompile. Đọc thêm tại đây
Sung Cho

Tuyên bố đã được di chuyển. Tôi đang chạy ray 4.2.0. và thấy nhận xét này trong file production.rb: # config.assets.precompileconfig.assets.versionđã chuyển sang config / initializers / assets.rb
cộc lốc

11

Tôi thích những điều sau đây ...

Trong tệp application_helper.rb của bạn

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

và sau đó trong chế độ xem cụ thể của bạn (ứng dụng / lượt xem / sách / index.html.erb trong ví dụ này)

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

... Dường như làm việc cho tôi.


9

Nếu bạn không muốn sử dụng đường dẫn tài sản hoặc công việc phức tạp xung quanh để có được javascript cụ thể của trang đó (tôi đồng cảm), cách đơn giản và mạnh mẽ nhất, đạt được như các câu trả lời ở trên nhưng với ít mã hơn chỉ là sử dụng:

<%= javascript_include_tag "my_javascipt_file" %>

Lưu ý: điều này không yêu cầu thêm một yêu cầu http cho mỗi thẻ bao gồm các câu trả lời sử dụng content_for :head


javascript_include_tagchính xác là những gì tôi đang tìm kiếm, chúc mừng AJP
Tom McKenzie

bạn đặt "my_javascipt_file" ở đâu? Trong tài sản / javascripts? Nhưng nếu vậy, điều đó có được chọn tự động với một //= require .trong application.js không?
qix

@Linus yep, //= require .sẽ mang tập lệnh đó vào bất kỳ trang nào trên trang web của bạn để bạn phải làm một cái gì đó như Kenny Grant (sử dụng //= require_tree ./global) hoặc bjg đề xuất.
AJP

1
Đây là phương pháp đơn giản nhất đối với tôi, tôi đã đổi //= require_tree .thành //= require_directory .application.js và sau đó tạo một thư mục con trong nội dung \ javascripts. Lưu ý rằng bạn phải bao gồm thư mục mới trong config \ initators \ nội dung.rb để biên dịch trước js của bạn bằng cách thêm dòng:Rails.application.config.assets.precompile += %w( new_dir/js_file.js )
Jonesy


3

Tôi hiểu rằng đường ống tài sản có nghĩa là giảm thời gian tải trang bằng cách trộn tất cả các js của bạn lại với nhau thành một tệp (rút gọn). Mặc dù điều này có vẻ khó chịu trên bề mặt, nhưng đây thực sự là một tính năng đã tồn tại trong các ngôn ngữ phổ biến như C và Ruby. Những thứ như thẻ "bao gồm" có nghĩa là ngăn chặn việc bao gồm nhiều tệp và để giúp các lập trình viên sắp xếp mã của họ. Khi bạn viết và biên dịch một chương trình trong C, tất cả mã đó có trong mọi phần của chương trình đang chạy của bạn, nhưng các phương thức chỉ được tải vào bộ nhớ khi mã đó đang được sử dụng. Theo một nghĩa nào đó, một chương trình được biên dịch không bao gồm bất cứ điều gì để đảm bảo rằng mã được mô-đun độc đáo. Chúng tôi tạo mã theo mô-đun bằng cách viết các chương trình theo cách đó và hệ điều hành chỉ tải vào bộ nhớ các đối tượng và phương thức chúng tôi cần cho một địa phương nhất định. Thậm chí còn có một thứ gọi là "bao gồm phương pháp cụ thể"? Nếu ứng dụng rails của bạn không hoạt động, đây thực chất là những gì bạn đang yêu cầu.

Nếu bạn viết javascript của mình để nó tăng cường hoạt động của các thành phần HTML trên trang, thì các chức năng đó là 'cụ thể theo trang' theo thiết kế. Nếu có một số mã phức tạp mà bạn đã viết theo cách nó sẽ thực thi bất kể bối cảnh của nó, có thể xem xét ràng buộc mã đó với một phần tử html (bạn có thể sử dụng thẻ body, như được mô tả trong phương thức Garber-Irish ). Nếu một hàm thực thi có điều kiện, hiệu suất có thể sẽ nhỏ hơn tất cả các thẻ script bổ sung đó.

Tôi đang nghĩ đến việc sử dụng đá quý paloma , như được mô tả trong dự án ứng dụng rails . Sau đó, bạn có thể làm cho trang javascript của mình cụ thể bằng cách bao gồm các chức năng dành riêng cho trang trong một cuộc gọi lại paloma:

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

Bạn sử dụng đường ray, vì vậy tôi biết bạn yêu thích đá quý :)


3

Bạn không nên tải các tệp JS hoặc CSS bên ngoài đường dẫn tài sản vì bạn mất đi các tính năng quan trọng khiến Rails trở nên tuyệt vời. Và bạn không cần một viên ngọc khác. Tôi tin rằng sử dụng càng ít đá quý càng tốt và sử dụng đá quý không cần thiết ở đây.

Những gì bạn muốn được gọi là "Javascript cụ thể của trình điều khiển" ("Javascript cụ thể hành động được bao gồm ở phía dưới). Điều này cho phép bạn tải một tệp JavaScript cụ thể cho một CONTROLLER cụ thể. Cố gắng kết nối Javascript của bạn với Chế độ xem là một loại .. ngược và không tuân theo mẫu thiết kế MVC. Bạn muốn liên kết nó với Bộ điều khiển hoặc hành động bên trong Bộ điều khiển của bạn.

Thật không may, vì bất kỳ lý do gì, các nhà phát triển Rails đã quyết định rằng theo mặc định, mọi trang sẽ tải mọi tệp JS nằm trong thư mục tài sản của bạn. Tại sao họ quyết định làm điều này thay vì bật "Trình điều khiển cụ thể Javascript" theo mặc định tôi sẽ không bao giờ biết. Điều này được thực hiện thông qua tệp application.js, bao gồm dòng mã sau theo mặc định:

//= require_tree .

Điều này được gọi là một chỉ thị . Đó là những gì sprockets sử dụng để tải mọi tệp JS trong thư mục tài sản / javascripts. Theo mặc định, sprockets tự động tải application.js và application.css và lệnh direct_tree tải mọi tệp JS và Coffee trong các thư mục tương ứng của chúng.

LƯU Ý: Khi bạn tạo giàn giáo (nếu bạn không lắp giàn giáo, bây giờ là thời điểm tốt để bắt đầu), Rails sẽ tự động tạo một tệp cà phê cho bạn, cho bộ điều khiển của giàn giáo đó. Nếu bạn muốn nó tạo tệp JS tiêu chuẩn thay vì tệp cà phê , thì hãy xóa đá quý cà phê được bật theo mặc định trong Gemfile của bạn và thay vào đó, giàn giáo của bạn sẽ tạo tệp JS.

Ok, vì vậy bước đầu tiên để bật "Javascript cụ thể của trình điều khiển" là xóa mã request_tree khỏi tệp application.js của bạn, HOẶC thay đổi nó thành một thư mục trong thư mục tài sản / javascripts của bạn nếu bạn vẫn cần các tệp JS toàn cầu. I E:

//= require_tree ./global

Bước 2: Đi vào tệp cấu hình / bộ khởi tạo / tài sản.rb của bạn và thêm vào như sau:

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

Chèn tên điều khiển mà bạn muốn.

Bước 3: Thay thế tệp javascript_include_tag trong tệp application.html.erb của bạn bằng phần này (lưu ý phần params [: controller]:

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

Khởi động lại máy chủ của bạn và viola! Tệp JS được tạo bằng giàn giáo của bạn bây giờ sẽ chỉ tải khi bộ điều khiển đó được gọi.

Cần tải một tệp JS cụ thể trên một HÀNH ĐỘNG cụ thể trong bộ điều khiển của bạn , IE / bài viết / mới ? Thay vào đó, hãy làm điều này:

application.html.erb :

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

cấu hình / khởi tạo / tài sản.rb :

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

Sau đó, thêm một thư mục mới có cùng tên với bộ điều khiển của bạn trong thư mục tài sản / javascripts của bạn và đặt tệp js của bạn có cùng tên với hành động của bạn bên trong. Sau đó nó sẽ tải nó vào hành động cụ thể đó.


1

Ok có lẽ đây giống như công việc tồi tệ nhất từ ​​trước đến giờ nhưng tôi tạo ra một phương thức điều khiển chỉ hiển thị tệp .js

Bộ điều khiển

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

Lượt xem

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

Nếu vì lý do nào đó chúng tôi không muốn làm điều này thì hãy cho tôi biết.


1

Cách ưa thích để thêm JS là ở chân trang, vì vậy bạn có thể làm theo cách này:

show.html.erb:

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

bố cục / application.html.erb

<%= yield :footer_js %>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.