Rails 3.1を使用して、「ページ固有」のJavaScriptコードをどこに配置しますか?


388

私の理解では、JavaScriptはすべて1つのファイルにマージされます。Railsは//= require_tree .application.jsマニフェストファイルの最後に追加すると、デフォルトでこれを行います。

これは本当の命の恩人のように聞こえますが、ページ固有のJavaScriptコードについて少し心配しています。このコードはすべてのページで実行されますか?最後に必要なのは、すべてのオブジェクトが1ページでのみ必要なときに、すべてのオブジェクトをインスタンス化することです。

また、コードが衝突する可能性もありませんか?

あるいはscript、ページのJavaScriptコードを実行するメソッドを呼び出すだけの小さなタグをページの下部に配置しますか?

その後、require.jsは必要なくなりましたか?

ありがとう

編集:私はすべての答えに感謝しています...そして私は彼らが本当に問題になっているとは思いません。それらのいくつかはスタイリングに関するものであり、関連しているようには見えません...そして他の人はjavascript_include_tag私が存在することを知っていると述べています...各ページの下部で個々のJavaScriptをロードするのではなく、JavaScriptを1つのファイルに読み込みます。

私が思いつくことができる最善の解決策は、特定の機能dividsまたはclasses でタグにラップすることです。JavaScriptコードでは、idまたはclassがページ上にあるかどうかを確認し、ページ上にある場合は、それに関連付けられているJavaScriptコードを実行します。このように、動的要素がページ上にない場合、JavaScriptコードはapplication.js、Sprocketsによってパッケージ化された巨大なファイルに含まれていても実行されません。

私の上記のソリューションには、100ページのうち8ページに検索ボックスが含まれている場合、その8ページのみで実行されるという利点があります。また、サイトの8ページに同じコードを含める必要はありません。実際、サイトに手動のスクリプトタグを含める必要はもう二度とありません。

これが私の質問に対する実際の答えだと思います。


11
「今後のRails 3.1の方法は、各ページの下部で個々のJavascriptをロードするのではなく、すべてのJavascriptを1つのファイルにまとめることです。」-Railsコアチームがこれまでも、そしてこれまでも、 JavaScriptを管理します。小さなファイルの方が一般的には優れています(他の場所にある私のコメントを参照してください)。JavaScriptに関して言えば、Railsの方法が正しい方法であることはめったにありません(お尻を蹴るアセットパイプラインと、CoffeeScriptの推奨を除く)。
Marnen Laibow-Koser 2012

それで、すべてのページにページ固有のjsファイルを含めますか?それはもったいないと思います。ClosureCowboyの答えにはもっと同意します。
2012

1
この質問に対する受け入れられた回答を確認しましたか?stackoverflow.com/questions/6571753/...
rassom

1
@DutGRIFF言い換えれば、いいえ、この場合、Railsの方法で行うことは最善ではありません(または、少なくともすべてをに入れないでくださいapplication.js)。実際、あなたが提供した参照は、これがそうである理由を指摘しています。 JS実行プロセスの最も遅い部分。多くの小さなファイルは、1つの大きなファイルよりもキャッシュ可能です。Unholy Railsの人々は、そのため、彼らの推奨事項が、守ろうとしている原則と矛盾していることを認識していないようで、したがって、彼らの推奨事項を真剣に受け止めるべきではありません。
Marnen Laibow-Koser 2014

1
@DutGRIFFいいえ、キャッシュされた後でも、通常、大きなJSファイルは適切ではありません。このページの他の場所にある私のコメントを参照してください。小さなファイルは特定のページをより的確に対象とすることができ、より細かい粒度でキャッシュできます。何ページ固有のコードが存在しない場合を除き、私は一つの大きなファイルのために何か良いユースケースが表示されていないすべてでは
Marnen Laibow-Koser 2014

回答:


157

アセットパイプラインのドキュメントは、コントローラー固有のJSの実行方法を提案しています。

たとえば、a ProjectsControllerが生成された場合、に新しいファイルがapp/assets/javascripts/projects.js.coffeeあり、に別のファイルがありますapp/assets/stylesheets/projects.css.scss。これらのファイルは、<%= javascript_include_tag params[:controller] %>またはなどの行を持つこれらのコントローラーに対してのみロードできるため、コントローラーに固有のJavaScriptまたはCSSをそれぞれのアセットファイル内に配置する必要があります<%= stylesheet_link_tag params[:controller] %>

リンク先:asset_pipeline


50
これは、最もエレガントな方法です。ただし、// = require_treeという行も削除する必要があります。application.js.coffeeから
zsljulius

2
私はこの方法に完全に同意します。他のメソッドは非常に不格好に見え、それでも巨大なjsファイルをロードすることになります。作業中のプロジェクトには、結合/縮小化した後のJSファイル/プラグインなどの約2MB相当があります。
Bill Garrison

2
私はRailsにかなり慣れていませんが、これがデフォルトの動作であるように思えます。
ロスハンブリック2013

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 2013年

2
コントローラ固有のアクションはまだ縮小されていますか?それらは、スプロケットによって作成される単一のjsファイルに追加されますか、それともエルクがアセットファイルの複数のリクエストにつながるのですか?
Jason

77

ページ固有のjsの場合、Garber-Irishソリューションを使用できます。

したがって、Rails javascriptsフォルダーは、2つのコントローラー(車とユーザー)の場合、次のようになります。

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

そして、JavaScriptは次のようになります。

// 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オブジェクトのコードが含まれ、DOM対応のUTIL.initの実行時に使用されます。

そして、これをレイアウトファイルに追加することを忘れないでください。

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

またdata-*、ページ固有のCSSを改善するために、属性の代わりにクラスを使用する方が良いと思います。Jason Garberが述べたように:ページ固有のCSSセレクターは非常に扱いにくいことがあります(data-*属性を使用する場合)

これがお役に立てば幸いです。


4
ユーザーコントローラーのすべてのアクションで使用できるが、他のコントローラーでは使用できない変数が必要な場合はどうしますか?この方法にはスコープの問題がありませんか?
tybro0103 2012年

@ tybro0103、私はこの動作を実装するためにwindow.varForOneController='val'、このコントローラのinit関数のようなものを書きたいと思います。また、gon gemも役立ちます(github.com/gazay/gon)。他の回避策があります。
welldan97

1
@ welldan97ダウン投票はあなたの説明ではありません-これはすばらしい-ですが、ガーバーアイリッシュの構造は悪いからです。すべてのJSをすべてのページにロードし、<body>要素のクラスとIDに依存して物事を分類します。これはDOMとの戦いの確実な兆候です。通常の状況では、<body>要素にはクラスまたはIDは必要ありません。ドキュメントには1つしか存在しないからです。これを行う適切な方法は、単にを削除して//= require_tree .、ページ固有のJavaScriptを使用することです。あなたが積極的にそれをしないようにしようとしているなら、あなたは悪い習慣のために努力しています。
Marnen Laibow-Koser

2
@ MarnenLaibow-Koser個人的には、すべてのjsを1つのファイルに結合して最小化する場合、ほとんどのプロジェクトですべてのページにすべてのjsをロードするのが良いと思います。ユーザーにとっては全体的に速く機能すると思います。少なくとも、1つのjsファイルと多くのファイルが競合しているようです(つまり、stackoverflow.com / questions / 555696 /…を見てください)。また、コードを単純化して機能するのであれば、ボディでクラスとIDを使用しても問題はありません。Modernizr(modernizr.com)はこれを行い、他のいくつかのライブラリも同様です。
welldan97

2
@ MarnenLaibow-Koser Railsアセットパイプラインは、コンパイルと比較するのに適した候補のようです。プログラマーはjavascriptを分離された素敵なモジュールで記述し、それをひとまとめにして、縮小し、提供します。コンパイルされた言語の場合と同様に、コンパイラーよりも一歩先を行っていると考えるプログラマーは常に存在します。しかし、これはほとんど真実ではないと思います。
Ziggy

65

あなたはあなた自身の質問に答えたようですが、ここに別のオプションがあります:

基本的に、あなたは

//= require_tree .

必要とされている。そうではありません。気軽に外してください。現在のアプリケーションでは、最初に正直に3.1.xを使用して、3つの異なるトップレベルの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次のプリプロセッサディレクティブを含めることができます。//=

ClosureCowboyの回答にいくつかの詳細が役立ち、追加されることを願っています。

スジャル


8
+1これは私のような初心者にとって知っておくと便利です。できれば+2あげます。
jrhorn424 2012年

5
@sujalその通りです。Railsのコアチームは、ひどいJavaScript管理で有名です。彼らの提案を無視して、アセットパイプラインの良い部分だけを使ってください。:)
Marnen Laibow-

1
このアドバイスをどうもありがとう。アプリのモジュールによっては、「トップレベル」のJSファイルがいくつかありません。うまくいきます。
elsurudo 2013

1
私のためにここに+1の重要なポイントは、置き換えることができるということである//= require_tree .//= require_directory .あなたは彼らがすべての既存のファイルを保持し、ページの特定のファイルの新しいディレクトリを作成することができるように。
zelanix 2014年

41

別のオプション:ページまたはモデル固有のファイルを作成するには、assets/javascripts/フォルダー内にディレクトリを作成します。

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

メインapplication.jsマニフェストファイルは、からファイルをロードするように設定できますglobal/。特定のページまたはページのグループは、独自の特定のディレクトリからファイルをロードする独自のマニフェストを持つことができます。Sprocketsはによって読み込まれたファイルをapplication.jsページ固有のファイルと自動的に結合します。これにより、このソリューションが機能します。

この手法はstyle_sheets/、同様に使用できます。


13
あなたは今私にカップケーキを渇望させました。
チャックベルジェロン

私はこのソリューションが本当に好きです。私が抱えている唯一の問題は、それらの余分なマニフェストが圧縮/醜化されていないことです。それらは適切にコンパイルされていますが。解決策はありますか、それとも何か不足していますか?
clst

1
これは、ブラウザーが1つのjsファイル、つまりグローバル+ページ固有のファイルの組み合わせをロードすることを意味しますか?
lulalala

利用できる場合、私の質問を見てください。stackoverflow.com/questions/17055213/...
マクシムスS

1
@clstこれはあなたが探している答えだと思います:guides.rubyonrails.org/asset_pipeline.html#precompiling-assets
FrontierPsycho

23

私はすべての答えに感謝します...そして、彼らが本当に問題に取り組んでいるとは思いません。それらのいくつかはスタイリングに関するものであり、関連していないようです...そして他の人はjavascript_include_tag私が存在することを知っていると述べています(明らかに...)が、Rails 3.1の今後の方法はすべてをまとめることです各ページの下部に個々のJavaScriptをロードするのではなく、JavaScriptを1つのファイルに。

私が思いつくことができる最善の解決策は、特定の機能dividsまたはclasses でタグにラップすることです。JavaScriptコード。次に、idまたはclassがページ上にあるかどうかを確認し、ある場合は、それに関連付けられているJavaScriptコードを実行します。このように、動的要素がページ上にない場合、JavaScriptコードはapplication.js、Sprocketsによってパッケージ化された大規模なファイルに含まれていても実行されません。

私の上記のソリューションには、100ページのうち8ページに検索ボックスが含まれている場合、その8ページのみで実行されるという利点があります。また、サイトの8ページに同じコードを含める必要はありません。実際、データをプリロードする場合を除いて、手動のスクリプトタグをサイトに含める必要はもうありません。

これが私の質問に対する実際の答えだと思います。


しかし、実際にはそれらの手動<script>タグが必要です。はい、クラスとIDは答えの一部ですが、ユーザーがその特定のページで必要としないJavaScriptをロードすることは意味がありません。
Marnen Laibow-Koser

4
@ MarnenLaibow-Koser一意の各ページに手動スクリプトタグを追加しない理由は、すべてのページビューでそのスクリプトコンテンツをダウンロードする必要があるためです。アセットパイプラインを使用してすべてのjavascriptをapplication.jsにパッケージ化できる場合、ユーザーはそれらのスクリプトを1回だけダウンロードし、後続のすべてのページロードでapplication.jsをキャッシュからプルします
jakeonrails

@jakeonrails "各固有のページに手動スクリプトタグを追加しない理由は、すべてのページビューでそのスクリプトコンテンツをダウンロードする必要があるためです"-間違いです。スクリプトは一度ダウンロードされ、その後のリクエストでブラウザのキャッシュからフェッチされます。「アセットパイプラインを使用してすべてのjavascriptをapplication.jsにパッケージ化できる場合、ユーザーはそれらのスクリプトを1回だけダウンロードします」-trueですが、不必要なコードが大量に消費されます。JSを1つの大きなファイルではなく、多くの小さなファイルに構造化できる場合、不要なコードなしでキャッシュの利点を得ることができます。
Marnen Laibow-Koser 2013

1
@ MarnenLaibow-Koserすべてを1つのスクリプトにパッケージ化した場合、ユーザーはサイトのページごとに1つのスクリプトをダウンロードするだけでよいと言った方がいいでしょう。アプリのさまざまな部分に複数のスクリプトがある場合、ユーザーは複数のスクリプトをダウンロードする必要があります。もちろん、両方の方法がキャッシュされますが、ほとんどの場合(中小規模のアプリ)、1つのapplication.jsを1回提供するだけでダウンロードの効率が向上します。JSの解析は、提供する内容によっては別の話になる場合があります。
jakeonrails 2013年

1
@Ziggyまた、小さなファイルが100ページのうち8ページでのみ使用されている場合、コードが常にユーザーのキャッシュに常駐する必要があるのはなぜですか。不要なものを実際にドロップする方が良いでしょう。
Marnen Laibow-Koser 2013

16

私はこのパーティーに少し遅れて来ることに気づきましたが、私が最近使用しているソリューションを投入したかったのです。ただし、最初に触れさせてください...

Rails 3.1 / 3.2 Way(いいえ、私はそれが好きではありません。)

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

私はこの回答に完全を期すために以下を含めています。それは実行不可能な解決策ではないので...あまり気にしませんが。

「Rails Way」は、この質問の元の著者が要求したようにビュー指向ではなく、コントローラー指向のソリューションです。それぞれのコントローラーにちなんで命名されたコントローラー固有のJSファイルがあります。これらのファイルはすべて、デフォルトではapplication.jsのrequireディレクティブに含まれていないフォルダーツリーに配置されます。

コントローラ固有のコードを含めるには、ビューに次のコードを追加します。

<%= javascript_include_tag params[:controller] %>

私はこの解決策を嫌っていますが、それはそこにあり、迅速です。おそらく、代わりにこれらのファイルを「people-index.js」や「people-show.js」のような名前で呼び出し"#{params[:controller]}-index"、ビュー指向のソリューションを取得するようなものを使用できます。繰り返しになりますが、すぐに修正できますが、うまく対応できません。

私のデータ属性方法

クレイジーと呼んでも、デプロイするときにすべてのJSをコンパイルしてapplication.jsに縮小したい これらの小さなstragglerファイルをあちこちに含めることを覚えておく必要はありません。

私はすべてのJSを1つのコンパクトなブラウザーにキャッシュされるファイルにロードします。私のapplication.jsの特定の部分をページで起動する必要がある場合は、RailsではなくHTMLに通知させます。

JSを特定の要素IDにロックしたり、マーカークラスでHTMLを散らかしたりするのではなく、というカスタムデータ属性を使用しますdata-jstags

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

各ページで、使用するJSライブラリメソッドをここに挿入して、DOMの読み込みが完了したときにコードを実行します。このブートストラップコードは、次のアクションを実行します。

  1. でマークされたDOM内のすべての要素を反復処理します data-jstag
  2. 要素ごとに、属性値をスペースで分割し、タグ文字列の配列を作成します。
  3. タグ文字列ごとに、そのタグのハッシュで検索を実行します。
  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
};

ブートストラップイベントは、検索入力に対してmy_autosuggest_initmy_hint_init関数を適用し、ユーザーが入力しているときに候補のリストを表示する入力に変換し、入力が空白でフォーカスされていない場合に何らかの入力ヒントを提供します。

一部の要素がでタグ付けされていない限りdata-jstag="auto-suggest"、自動提案コードは実行されません。しかし、それは常にそこにあり、縮小され、最終的に私のapplication.jsにキャッシュされます。

タグ付けされたJS関数に追加のパラメーターを渡す必要がある場合は、いくつかの創造性を適用する必要があります。data-paramter属性を追加するか、ある種のパラメーター構文を考え出すか、ハイブリッドアプローチを使用します。

コントローラー固有の複雑なワークフローがある場合でも、そのためのファイルをlibフォルダーに作成し、application.jsにパックして、「new-thing-wizard」などのタグを付けます。ブートストラップがそのタグに当たると、素敵で豪華なウィザードがインスタンス化されて実行されます。必要なときにそのコントローラーのビューに対して実行されますが、それ以外の場合はコントローラーに結合されません。実際、ウィザードを正しくコーディングすれば、すべての構成データをビューに提供できるため、ウィザードを必要とする他のコントローラーに後で再利用できる可能性があります。

とにかく、これは私がしばらくページ固有のJSを実装してきた方法であり、単純なサイト設計とより複雑でリッチなアプリケーションの両方に役立ちました。私がここで紹介した2つのソリューションのうちの1つ(私の方法またはRailsの方法)が、将来この問題に遭遇した人にとって役立つことを願っています。


6
ちょっとした詳細:jsがブラウザにキャッシュされたら、影響がないというのはあなたの答えにこの概念があります。これはまったく真実ではありません。jsファイルが適切にキャッシュされている場合、ブラウザーは実際にダウンロードを回避しますが、すべてのページレンダリングでコードをコンパイルします。したがって、トレードオフのバランスを取る必要があります。多数のJSがあり、ページごとに一部しか使用されない場合、JSを分解することでページ時間を改善できる可能性があります。
sujal

私が話していることコンパイル手順の実用的な効果の詳細については、ベースキャンプ次pjaxが影響を受けたかの37本の信号説明を参照してください。37signals.com/svn/posts/...
sujal

それは公平な点です。記事を読み、上記のソリューションを使用したプロジェクトを振り返ると、記事で言及している「変更されたHTMLを送信する」ソリューションと基本的に同じものを書いたことがわかりました。そのため、JSの頻繁な再コンパイルは、私のプロジェクトでは問題になりませんでした。コンパイル手順は、「デスクトップアプリケーション」志向の少ないサイトで作業する場合に心に留めておくべきことです。
ライアン

2
「クレイジーと呼んでください。でも、デプロイするときにすべてのJSをapplication.jsにコンパイルして縮小したいのです」という反対投票。ユーザーが不要なJavaScriptをロードし、ハンドラーがそこにない属性を探すようになるので、これは本当に必要ありません。app.jsにすべてを含めることは魅力的であり、Railsは確かにそれを容易にしますが、適切なことはJavaScriptをより適切にモジュール化することです。
Marnen Laibow-Koser

あなたには別の意見が与えられます...そして技術的には意見の違いに対して反対投票する権利があります。ただし、1つの大きなキャッシュファイルがモジュール化されたJSを取得するために複数のHTTPリクエストを強制するよりもなぜ劣るのかについて、いくつかの正当化を見るとよいでしょう。さらに、ハンドラーの検索手順について誤解されています。タグ値は検索されません。検索は1回だけ実行され、data-jstag属性を持つすべての要素が取得されます。タグ名で検索するのではなく、タグを持つすべての要素を見つけて、必要なオブジェクトのみをインスタンス化します。
ライアン

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レイアウトファイルで、新しいヘルパーを既存のJavaScriptインクルードに追加し、rawヘルパーをプレフィックスとして追加します。

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

これで、レール内の他の場所で使用しているのと同じファイル構造を使用して、ビュー固有のJavaScriptを簡単に作成できるようになりました。単にファイルをに貼り付けてくださいapp/assets/:namespace/:controller/action.js.erb

それが他の誰かを助けることを願っています!


1
これにより、アセットがプリコンパイルされた後に問題が発生し、実行時に<%= raw ... %>404が返されますか?
Nishant 2013年

アセットパイプラインは、あまり使用されるべきではないファイルの束を作成するため、甘くないと思います。したがって、私にとってアセットパイプラインに依存すると、非効率的なシステムへの依存が生まれます。
デボラ

1
@DeborahSpeeceアセットパイプラインはいつ使用してはならないファイルを作成しますか?アセットパイプライン(良い)とrequire_tree /(悪い)を混同していますか?
Marnen Laibow-Koser 2013

6

この行をレイアウトファイル(application.html.erbなど)に追加して、コントローラー固有のjavascriptファイル(コントローラーの生成時に作成されたファイル)を自動的にロードできます。

<%= javascript_include_tag params[:controller] %>

また、アクションごとにスクリプトファイルを自動的に読み込む行を追加することもできます。

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

コントローラー名にちなんだ名前のサブディレクトリにページスクリプトを配置するだけです。これらのファイルには、= requireを使用して他のスクリプトを含めることができます。ブラウザで404エラーが発生しないように、ファイルが存在する場合にのみファイルを含めるヘルパーを作成すると便利です。


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

2
これは質問に答えられる可能性があるようです。それを具体化するための回答にさらに追加していただけませんか?


5

LoadJSの宝石は別のオプションです。

LoadJSは、Sprocketsが提供する魔法を失うことなく、Railsアプリにページ固有のJavaScriptコードをロードする方法を提供します。すべてのJavaScriptコードは1つの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>事実上正しくありません。このページの他の場所にある私のコメントを参照してください。
Marnen Laibow-Koser 2012

これを行わないでください。ここでの問題は、これらのいずれかを追加するたびに、ページの読み込み時に実行する必要のある別のjsを追加することです。プロジェクトの成長に伴い、パフォーマンスが低下する可能性があります。
ifightcrime 2015年

2

JavaScriptは、Rails(むしろSprockets)にマージするように指示した場合にのみマージされます。


もちろん。Railsのデフォルトにはフォルダー内のすべてが含まれているので、私は尋ねると思います...つまり、Davidはあなたがそうすることを意図しています。しかし、@ ruby​​princeへの他のコメントで述べたように、この方法で実行された場合の実行については不明です。無効にする必要があると思い//= require_tree .ますか?
ファイアーエムブレム

@FireEmblemはい。require_tree .通常は悪い考えです。
Marnen Laibow-Koser 2012

2

これは私がスタイリングの問題を解決した方法です:(申し訳ありませんがHaml)

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

このようにして、すべてのページ固有の.css.sassファイルを以下で開始します。

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

これにより、衝突を簡単に回避できます。.js.coffeeファイルに関しては、次のような要素を初期化できます。

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

これが一部に役立つことを願っています。


1
最後のビットをもう一度読んでください。JavaScriptの場合、ビュー固有の関数を初期化するためにスタイルシートに使用されているのと同じ構造を利用できます。
Zeeraw、2011年

フィリップ、$('#post > #edit') ->無効のようです。スコープ内で動作するようにjQueryをどのようにスコープしますか?
Ramon Tayag、2009

2
最近、application.html.hamlでこれを呼び出すことにより、すべてのコントローラー固有のJavaスクリプトとスタイルシートの読み込みを開始しました。= javascript_include_tag "application"そして、= javascript_include_tag params[:controller]私はjavascriptのコードを維持することができ、この方法は、ファイルのスコープの内部を指定しなくても限られました。
zeeraw


2

私はあなたの答えに同意します、そのセレクターがそこにあるかどうかを確認するには、次を使用します:

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

(実際のソリューションを追加する人は誰もいませんでした)


2

本当にすべてをまとめてあなたのためにレイアウトする答えは見当たりません。したがって、私はmeleyalsujalClasureCowboyの1 )、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!"


簡単な説明

  • application.js//= require_tree .から削除し、各ページが共有するJSのみをリストします

  • 上記のapplication.html.erbの2行は、application.jsとページ固有のJSを含める場所をページに伝えます。

  • 上記のindex.html.erbに示されている3行は、ページ固有のJSを探し、それを ":javascript"(または名前を付けたいもの)と呼ばれる名前付き利回り領域に含めるようにビューに指示しています。この例では、コントローラーは「foo」であるため、Railsはアプリケーションレイアウトの:javascript収量領域に「foo.js」を含めようとします。

  • ページ固有のJSをfoo.js(またはコントローラーの名前が付けられているもの)にリストします。一般的なライブラリ、ツリー、ディレクトリなどをリストします。

  • カスタムページ固有のJSは、他のカスタムJSとは別に簡単に参照できる場所に保管してください。この例では、foo.jsははそうのような、そこにカスタムJSを置くfoostuffツリーを必要とfoothis.js.coffee

  • ここには厳しいルールはありません。自由に移動して、必要に応じて、さまざまなレイアウトでさまざまな名前の複数の出力領域を作成してください。これは、前進する可能性のある最初のステップの1つを示しています。(Backbone.jsを使用しているため、このように正確に実行することはしません。foostuffの代わりにfoo.jsをfooというフォルダーにドロップすることもできますが、まだ決定していません。)

ノート

CSSでも同様のことができます<%= stylesheet_link_tag params[:controller] %>が、これは問題の範囲を超えています。

ここで明白なベストプラクティスを逃した場合は、私にメモを送ってください。Railsは私にとってはかなり新しいものであり、正直なところ、これまでのところデフォルトでエンタープライズ開発にもたらされる混乱と、平均的なRailsプログラムが生成するすべてのトラフィックにはそれほど感心していません。


これは進むべき道のようです、私は自分のアプリにそれを実装できるかどうかを確認します。詳細な回答に感謝します。
martincarlin87 2015

1

私は別の解決策を持っていますが、プリミティブはうまく機能し、ファンシーな選択的ロード戦略は必要ありません。通常のドキュメントレディ関数を挿入しますが、現在のウィンドウの場所をテストして、JavaScriptが対象としているページであるかどうかを確認します。

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

これにより、すべてのjsを1つの小さなパッケージでrails 3.xによってロードできるようになりますが、オーバーヘッドが大きくなったり、jsが意図していないページと競合したりすることはありません。


1

ryguyの回答は良い回答ですが、否定的な点に反対票が投じられました。

特にBackbone JSのようなものを使用している場合-各ページには独自のBackboneビューがあります。次に、erbファイルには、正しいバックボーンビュークラスを起動するインラインJavaScriptが1行だけ含まれています。私はそれを「接着剤コード」の1行とみなしているため、そのインラインは問題ありません。利点は、ブラウザがすべてのJavaScriptをキャッシュできるようにする「require_tree」を維持できることです。

show.html.erbでは、次のようになります。

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

レイアウトファイルには、次のものが必要です。

<%= yield :javascript %>

反対投票。インラインJavaScriptは決して良い考えではありません。それがグルーコードであっても、それは外部ファイルにあるべきです。
Marnen Laibow-Koser 2014

1

すべての一般的なJSファイルを 'app / assets / javascript / global'のようなサブフォルダーに移動し、application.jsで//= require_tree .行をに変更し//= require_tree ./globalます。

これで、コントローラー固有のJSを 'app / assets / javascript /'ルートに自由に配置でき、それらはコンパイルされたJSに含まれなくなり= javascript_include_tag、コントローラー/ビューで呼び出すときにのみ使用されます。


まさか、それは1つのページにロードするJavaScriptのクラップロードです。キャッシュされていても問題ありません。
jackyalcine

1

ここにいくつかの答えがありますが、おそらくあなたの編集が最善の策だと思います。私たちのチームでGitlabから入手した設計パターンは、ディスパッチャーパターンです。それはあなたが話していることと似たようなことをしますが、ページ名はRailsによってbodyタグに設定されます。たとえば、レイアウトファイルに(HAMLで)のようなものを含めるだけです。

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

次にdispatcher.js.coffee、次のように、javascriptsフォルダーのファイルに1つのクロージャーとswitchステートメントのみを含めます。

$ ->
  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プロジェクトは、ページ固有のJavaScriptコードを管理する興味深いアプローチを提供します。

彼らのドキュメントからの使用例:

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(デフォルトではrails)を編集します。次のタグに「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

私はこれを試していませんが、次のように見えます:

  • JavaScriptのcontent_forがある場合(たとえば、実際のJavaScriptが含まれている場合)、スプロケットはそれを認識しないため、これは現在と同じように機能します。

  • JavaScriptの大きなバンドルからファイルを除外する場合は、config / sprockets.ymlファイルに移動し、それに応じてsource_filesを変更します。次に、除外したファイルを必要な場所に含めるだけです。


ファイルを除外したり、ページ自体でカスタムJavaScriptを使用したりするのは「正しい方法」ですか?それはデビッドが人々にそれを使うことを意図した方法ですか?
ファイアーエムブレム

@FireEmblem DavidがJavaScriptを適切に構成する方法を理解していないと思うので、Davidの意図をあまり気にしません。
Marnen Laibow-Koser


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

layouts / 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

1つ目:\\=require_treeapplication.jsから削除2つ目:すべてのJSコードをに配置し/app/assets/javascritpt、すべてのCSSコードをに配置する必要があります/app/assets/stylesheets


-2

ライアンのリードに続いて、これが私がしたことです-

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}}

反対投票。これはeval途方もなく複雑です- ひびの入ったサーバーまたは悪意のあるユーザースクリプトによってHTMLが危険にさらされた場合、(に起因して)安全ではないことは言うまでもありません。
Marnen Laibow-Koser 2014

-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
反対投票。インラインJavaScriptはお勧めできません。HTMLにはマークアップのみを含める必要があります。JSとCSSは、別々の再利用可能なファイルにする必要があります。
Marnen Laibow-Koser 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.