web-dev-qa-db-ja.com

Rails 3アプリにページ固有のJavaScriptを追加する最良の方法は?

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をどこに/どのように含めるのですか?このJavaScriptはこの1つのビューにのみ適用されるため、application.jsファイルを埋めたくありません。どういうわけか各ページにカスタムJavaScriptファイルを含めるか、ヘッダーが検索するインスタンス変数にそれを挿入する必要がありますか?

156
Brian Armstrong

私がやりたいのは、ビューごとの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>
150
bjg

Javascriptを1ページだけに含める場合は、もちろんインラインでページに含めることができますが、javascriptをグループ化し、アセットパイプライン、縮小された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

Config/production.rbを編集して、この新しいjsマニフェストがロードされていることを確認してください

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

次に、ページレイアウトを調整して、ページヘッドに追加のjsを含めることができます。

<%= content_for :header %>   

次に、この特定のjsグループ(および通常のアプリケーショングループ)および/またはページ固有のjs、cssなどを含めるビューで:

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

もちろん、CSSを使用して同じことを行い、サイトの特定の領域にのみ適用するために同様の方法でグループ化することができます。

102
Kenny Grant

私は以下を好む...

Application_helper.rbファイル内

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

次に、特定のビュー(この例ではapp/views/books/index.html.erb)

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

...私のために働くようです。

12
cailinanne

これらの答えは私を助けてくれました!誰かがもう少し欲しいなら...

  1. プリコンパイルする場合は、JavaScriptをマニフェストに配置する必要があります。ただし、application.js.coffeeのすべてのjavascriptファイルが必要な場合、別のページに移動するたびにすべてのjavacsriptsが読み込まれ、ページ固有のjavascriptを実行する目的は無効になります。

したがって、ページ固有のすべてのJavaScriptファイルを必要とする独自のマニフェストファイル(例:speciifc.js)を作成する必要があります。また、require_treeapplication.jsから変更します

app/assets/javascripts/application.js

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

app/assets/javascripts/specific.js

//= require_tree ./specific

次に、environments/production.rbで、configオプションを使用してこのマニフェストをプリコンパイル済みリストに追加します。

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

できた!常にロードされるすべてのsharedJavaScriptはapp/assets/javascripts/globalフォルダーに配置され、ページ固有のJavaScriptはapp/assets/javascripts/specificに配置されます。次のようなビューからページ固有のJavaScriptを呼び出すことができます。

<%= javascript_include_tag "specific/whatever.js" %> //.jsはオプションです。

これで十分ですが、javascript_include_tag params[:controller]も使用したかったのです。コントローラーを作成すると、他の人が言及したように、関連するcoffeescriptファイルがapp/assets/javascriptsに生成されます。本当にコントローラー固有のJavaScriptがあり、ユーザーが特定のコントローラービューに到達したときにのみ読み込まれます。

そこで、別のマニフェストcontroller-specific.jsを作成しました

app/assets/javascripts/controller-specific.js

//= require_directory .

これには、コントローラーに関連付けられた自動生成されたすべてのコーヒースクリプトが含まれます。また、プリコンパイル済みリストに追加する必要があります。

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

11
Maximus S

アセットパイプラインまたは 複雑な回避策 を使用して、必要なページ固有のJavaScript(共感)を取得したくない場合は、上記の回答と同じことを達成する最も単純で最も堅牢な方法しかし、より少ないコードで使用するだけです:

<%= javascript_include_tag "my_javascipt_file" %>

注:これには、content_for :headを使用する回答よりもincludeタグごとにもう1つのhttpリクエストが必要です

9
AJP

pluggable_js gemをご覧ください。このソリューションは使いやすいかもしれません。

7
peresleguine

私の理解では、アセットパイプラインは、すべてのjsを1つの(縮小された)ファイルにまとめることにより、ページのロード時間を短縮することを目的としています。これは表面的には嫌に思えるかもしれませんが、実際にはCやRubyなどの一般的な言語に既に存在する機能です。 「インクルード」タグのようなものは、ファイルが複数インクルードされるのを防ぎ、プログラマーがコードを整理するのを支援するためのものです。 Cでプログラムを作成してコンパイルすると、そのコードはすべて実行中のプログラムのすべての部分に存在しますが、メソッドはそのコードが使用されているときにのみメモリにロードされます。ある意味では、コンパイルされたプログラムには、コードが適切にモジュール化されていることを保証するものは何も含まれていません。プログラムをそのように記述することでコードをモジュール化し、オペレーティングシステムは特定の地域に必要なオブジェクトとメソッドのみをメモリにロードします。 「メソッド固有のインクルード」などもありますか? Railsアプリが落ち着いている場合、これは基本的にあなたが求めているものです。

ページ上のHTML要素の動作を強化するようにJavaScriptを記述した場合、それらの機能は仕様により「ページ固有」です。コンテキストに関係なく実行されるように作成した複雑なコードがある場合は、とにかくそのコードをhtml要素にバインドすることを検討してください( Garber-アイルランドの方法 )。関数が条件付きで実行される場合、パフォーマンスはおそらくこれらすべての追加スクリプトタグよりも小さくなります。

Railsアプリプロジェクト で説明されているように、 paloma gemを使用することを考えています。次に、ページ固有の関数をpalomaコールバックに含めることにより、javascriptをページ固有にすることができます。

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

あなたはRailsを使用しているので、私はあなたが宝石を愛していることを知っています:)

3
Ziggy

Railsを非常に優れたものにする重要な機能を失うため、アセットパイプラインの外部でJSまたはCSSファイルをロードしないでください。そして、あなたは別の宝石を必要としません。私はできるだけ少ない宝石を使用することを信じており、ここでは宝石を使用する必要はありません。

必要なものは「コントローラー固有のJavascript」と呼ばれます(「アクション固有のJavascriptが下部に含まれています)。これにより、特定のコントローラーの特定のJavaScriptファイルをロードできます。Javascriptをビューに接続しようとするとMVC設計パターンに従っていないため、コントローラーまたはコントローラー内のアクションに関連付ける必要があります。

残念ながら、何らかの理由で、Rails devsは、デフォルトで、すべてのページがアセットディレクトリにあるすべてのJSファイルをロードすることを決定しました。彼らがデフォルトで「Controller Specific Javascript」を有効にする代わりにこれを行うことにした理由は、私には決してわかりません。これは、デフォルトで次のコード行を含むapplication.jsファイルを介して行われます。

//= require_tree .

これは、ディレクティブとして知られています。これは、sprocketsがasset/javascriptsディレクトリ内のすべてのJSファイルをロードするために使用するものです。デフォルトでは、スプロケットはapplication.jsとapplication.cssを自動的にロードし、require_treeディレクティブはそれぞれのディレクトリにあるすべてのJSとCoffeeファイルをロードします。

注:足場を作成するとき(足場を作成していない場合は、今から始めるのが良いタイミングです)、Railsは自動的にcoffeeファイルを生成します、そのscaffoldのコントローラー用。 coffeeファイルではなく標準JSファイルを生成する場合は、coffee gemを削除します。 Gemfile、そしてscaffoldは代わりにJSファイルを作成します。

OK、最初のステップ「Controller Specific Javascript」を有効にするには、application.jsファイルからrequire_treeコードを削除し、ORをasset/javascripts内のフォルダーに変更しますまだグローバルJSファイルが必要な場合は、ディレクトリ。 I.E .:

//= 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: application.html.erbファイルのjavascript_include_tagをこれに置き換えます(params [:controller]部分に注意してください:

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

サーバーとビオラを再起動してください!足場で生成されたJSファイルは、そのコントローラーが呼び出されたときにのみロードされるようになりました。

コントローラーの特定のACTIONで特定のJSファイルを読み込む必要があります、I.E. / articles/new?代わりにこれを行います:

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

次に、assets/javascriptsフォルダーにコントローラーと同じ名前の新しいフォルダーを追加し、アクションと同じ名前のjsファイルを内部に配置します。次に、その特定のアクションでそれをロードします。

3
Erick Maynard

わかりましたので、これはおそらく最悪の回避策のようですが、.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
Bill

JSを追加する好ましい方法はフッターなので、この方法で行うことができます。

show.html.erb:

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

layouts/application.html.erb

<%= yield :footer_js %>
1
Syed