Rails 3.1을 사용하면 "페이지 특정"JavaScript 코드를 어디에 배치합니까?


388

이해하기 위해 모든 JavaScript가 1 파일로 병합됩니다. Rails는 매니페스트 파일 //= require_tree .의 맨 아래에 추가 할 때 기본적으로이 작업을 수행 application.js합니다.

이것은 실제 생명을 구하는 것처럼 들리지만 페이지 별 JavaScript 코드에 대해서는 약간 걱정이됩니다. 이 코드는 모든 페이지에서 실행됩니까? 마지막으로 원하는 것은 모든 객체가 1 페이지에서만 필요할 때 모든 페이지에 대해 인스턴스화되는 것입니다.

또한 충돌하는 코드가있을 가능성이 있습니까?

아니면 script페이지 하단에 페이지의 자바 스크립트 코드를 실행하는 메소드를 호출 하는 작은 태그를 넣습니까?

더 이상 require.js가 필요하지 않습니까?

감사

편집 : 나는 모든 대답을 주셔서 감사합니다 ... 그리고 그들이 실제로 문제를 겪고 있다고 생각하지 않습니다. 그들 중 일부는 스타일링에 관한 것이며 관련이없는 것 같습니다 ... 그리고 다른 사람들은 javascript_include_tag내가 알고있는 ... (분명히 ...) 언급 하지만 Rails 3.1 방식은 모든 것을 마무리하는 것 같습니다. 각 페이지의 맨 아래에 개별 JavaScript를로드하는 대신 JavaScript를 1 개의 파일로로드하십시오.

내가 얻을 수있는 가장 좋은 해결책은 특정 기능 divids 또는 classes 로 태그로 묶는 것입니다. 자바 스크립트 코드에서, 당신은 단지 확인 경우 id또는 class페이지에 있고,이 경우, 당신은 그것과 관련된 자바 스크립트 코드를 실행합니다. 이렇게하면 동적 요소가 페이지에 없으면 JavaScript 코드는 application.jsSprockets에 의해 패키지 된 대규모 파일 에 포함되어 있어도 실행되지 않습니다 .

위의 솔루션은 100 페이지 중 8 페이지에 검색 상자가 포함되어 있으면 해당 8 페이지에서만 검색 상자가 실행된다는 이점이 있습니다. 또한 사이트의 8 개 페이지에 동일한 코드를 포함하지 않아도됩니다. 실제로 사이트에 수동 스크립트 태그를 다시 포함시킬 필요가 없습니다.

이것이 내 질문에 대한 실제 답변이라고 생각합니다.


11
"Rails 3.1의 발전 방법은 각 페이지 하단에 개별 Javascript를로드하는 대신 모든 Javascript를 하나의 파일로 마무리하는 것입니다."— Rails 핵심 팀만이 항상 그 방법을 아는 것이 사실 인 경우에만 JavaScript를 관리합니다. 작은 파일이 일반적으로 더 좋습니다 (다른 곳에서 내 의견 참조). JavaScript와 관련하여 Rails 방식은 옳은 방법이 아닙니다 (자산 파이프 라인, 엉덩이를 걷어차 고 CoffeeScript를 장려하는 경우 제외).
Marnen Laibow-Koser

모든 페이지에 페이지 별 js 파일을 포함 시키겠습니까? 나는 그것이 낭비라고 생각합니다. 저는 ClosureCowboy의 답변에 더 동의합니다.
gerky

1
이 질문에 대한 답변을 보셨습니까? stackoverflow.com/questions/6571753/…
rassom

1
@DutGRIFF 다른 말로하면 : 아니요,이 경우 Rails 방식으로 작업하는 것이 가장 좋지 않습니다 (또는 적어도 모든 것을 넣지 마십시오 application.js). 실제로 제공 한 참조는 이것이 왜 그런지 지적합니다. JS 실행 프로세스의 가장 느린 부분. 많은 작은 파일이 하나의 큰 파일보다 캐시 가능합니다. Unholy Rails 사람들은 그들의 권장 사항이 준수하려는 원칙과 일치하지 않는다는 것을 인식하지 못하는 것이므로 권장 사항을 심각하게 받아들이지 않아야합니다.
Marnen Laibow-Koser

1
@DutGRIFF 아니요, 큰 JS 파일은 캐시 된 후에도 일반적으로 좋지 않습니다. 이 페이지의 다른 곳에서 내 의견을 참조하십시오. 작은 파일은 특정 페이지를 더 잘 타겟팅 할 수 있으며 더 세밀하게 캐시 할 수 있습니다. 더 페이지 특정 코드가 존재하지 않는 한 나는 하나의 큰 파일에 대한 좋은 유스 케이스가 표시되지 않습니다 전혀 .
Marnen Laibow-Koser

답변:


157

Asset Pipeline 문서는 컨트롤러 별 JS를 수행하는 방법을 제안합니다.

예를 들어, a ProjectsController가 생성되면에 새 파일이 app/assets/javascripts/projects.js.coffee있고에 다른 파일이 있습니다 app/assets/stylesheets/projects.css.scss. 이 파일은 다음 단지 같은 라인이 컨트롤러를로드 할 수있는 당신은, 각각의 자산 파일 내부의 컨트롤러에 자바 스크립트 나 CSS 독특한 하나를 넣어해야 <%= javascript_include_tag params[:controller] %>하거나 <%= stylesheet_link_tag params[:controller] %>.

링크 : asset_pipeline


50
이것이 가장 우아한 방법입니다. 또한 // = require_tree 줄을 제거해야합니다. application.js.coffee에서
zsljulius

2
나는이 방법에 전적으로 동의한다. 다른 방법은 매우 어색해 보이지만 여전히 거대한 js 파일을로드합니다. 작업중 인 프로젝트는 결합 / 축소 된 후 거의 2MB의 JS 파일 / 플러그인 등을 가지고 있습니다.
Bill Garrison

2
나는 Rails를 처음 접했지만 이것이 기본 동작이어야한다고 생각합니다.
Ross Hambrick

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

2
컨트롤러 별 작업이 계속 축소됩니까? 스프라켓에 의해 생성 된 단일 js 파일에 추가됩니까, 아니면 이로 인해 자산 파일에 대한 여러 요청이 발생합니까?
Jason

77

페이지 별 js의 경우 Garber-Irish 솔루션을 사용할 수 있습니다 .

따라서 Rails javascripts 폴더는 자동차와 사용자의 두 컨트롤러에서 다음과 같이 보일 수 있습니다.

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

그리고 자바 스크립트는 다음과 같습니다

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

@ tybro0103, window.varForOneController='val'이 컨트롤러 초기화 함수 와 같은 것을 작성하고 싶은이 동작을 구현한다고 생각 합니다. 또한 gon gem은 여기 ( github.com/gazay/gon )에서 도움을 줄 수 있습니다 . 다른 해결 방법이있을 수 있습니다.
welldan97

1
@ welldan97 당신의 설명을 위해 하향 투표하는 것은 – 그것은 훌륭합니다 – 그러나 Garber-Irish 구조는 사악하기 때문입니다. 모든 JS를 모든 페이지에로드하고 <body> 요소의 클래스와 ID에 따라 항목을 정렬합니다. 이것은 DOM과 싸우는 확실한 신호입니다. 일반적인 상황에서 <body> 요소는 문서에 하나만 있기 때문에 클래스 나 ID가 필요하지 않습니다. 이를 수행하는 올바른 방법은 //= require_tree .페이지 특정 JavaScript 를 제거 하고 사용하는 것입니다. 적극적으로 그렇게하지 않으려 고한다면 나쁜 연습을하려고 노력하는 것입니다.
Marnen Laibow-Koser 2016 년

2
@ MarnenLaibow-Koser 개인적으로 모든 j를 하나의 파일로 결합하고 최소화 할 때 모든 페이지에 모든 js를로드하는 것이 대부분의 프로젝트에 적합하다고 생각합니다. 나는 그것이 전반적으로 사용자에게 더 빨리 작동한다고 생각합니다. 적어도 하나의 js 파일과 많은 충돌이 있습니다 (예 : stackoverflow.com/questions/555696/… ). 또한 코드를 간단하게 만들고 작동하면 본문에 클래스와 ID를 사용하는 데 아무런 문제가 없습니다. Modernizr ( modernizr.com ) 이이 작업을 수행하고 다른 라이브러리도 수행합니다.
welldan97

2
@ MarnenLaibow-Koser는 철도 자산 파이프 라인을 컴파일과 비교하기에 좋은 후보로 보입니다. 프로그래머는 멋진 분리 된 모듈에 자바 스크립트를 작성하고 함께 묶고 축소하고 제공합니다. 컴파일 된 언어의 경우와 마찬가지로 항상 컴파일러보다 앞서 있다고 생각하는 프로그래머가있을 것입니다 ... 그러나 나는 이것이 사실이 아니라고 생각합니다.
Ziggy April

65

귀하가 본인의 질문에 답변 한 것으로 나타 났지만 여기에 다른 옵션이 있습니다.

기본적으로, 당신은 가정

//= require_tree .

필요합니다. 그렇지 않습니다. 자유롭게 제거하십시오. 현재 응용 프로그램에서 3.1.x로 처음으로 정직하게 작업하는 세 가지 다른 최상위 JS 파일을 만들었습니다. 내 application.js파일 만

//= require jquery
//= require jquery_ujs
//= require_directory .
//= require_directory ./api
//= require_directory ./admin

이런 식으로, 내가 필요로하는 것만 포함하는 자체 최상위 JS 파일을 사용하여 서브 디렉토리를 작성할 수 있습니다.

열쇠는 다음과 같습니다.

  1. 당신은 제거 할 수 있습니다 require_tree레일은 당신이 만드는 가정을 변경할 수 있습니다 -
  2. 이름에는 특별한 것이 없습니다 application.js. assets/javascript서브 디렉토리의 모든 파일 에는 프리 프로세서 지시문이 포함될 수 있습니다.//=

희망이 ClosureCowboy의 답변에 도움이되고 세부 사항을 추가합니다.

수잘


8
+1 이것은 저와 같은 초보자에게 정말 좋습니다. 가능하다면 +2를하겠습니다.
jrhorn424

5
@sujal 정확합니다. Rails 핵심 팀은 심오한 JavaScript 관리로 유명합니다. 제안을 무시하고 자산 파이프 라인 의 좋은 부분을 사용하십시오 . :)
Marnen Laibow-Koser 2016 년

1
이 조언에 감사드립니다. 내 앱의 모듈에 따라 여러 "최상위"JS 파일이 없습니다. 잘 작동합니다.
elsurudo

1
여기에 나를 위해 하나 중요한 점은 당신이 대체 할 수 있다는 점이다 //= require_tree .//= require_directory .당신이 그들이 페이지의 특정 파일에 대한 새로운 디렉토리를 만드는 기존의 모든 파일을 보관할 수 있습니다.
zelanix

41

다른 옵션 : 페이지 또는 모델 별 파일을 작성하기 위해 assets/javascripts/폴더 내에 디렉토리를 작성할 수 있습니다 .

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

기본 application.js매니페스트 파일은에서 파일을로드하도록 구성 할 수 있습니다 global/. 특정 페이지 또는 페이지 그룹은 자신의 특정 디렉토리에서 파일을로드하는 자체 매니페스트를 가질 수 있습니다. 스프로킷은로드 된 파일을 application.js페이지 특정 파일과 자동으로 결합 하여이 솔루션이 작동하도록합니다.

이 기술도 사용할 수 있습니다 style_sheets/.


13
컵 케이크를 갈망하게 만들었습니다. Dangit!
척 버거론

나는이 솔루션을 정말 좋아한다. 내가 가진 유일한 문제는 그러한 여분의 매니페스트가 압축 / 축소되지 않는다는 것입니다. 그래도 제대로 컴파일됩니다. 해결책이 있습니까, 아니면 뭔가 빠졌습니까?
clst

1
이것은 브라우저가 하나의 js 파일, 즉 전역 + 페이지 특정 파일의 조합을로드한다는 것을 의미합니까?
lulalala

가능한 경우 내 질문을 살펴볼 수 있습니까? stackoverflow.com/questions/17055213/…
Maximus S

1
@clst 나는 이것이 당신이 찾고있는 답변이라고 생각합니다 : guides.rubyonrails.org/asset_pipeline.html#precompiling-assets
FrontierPsycho

23

모든 답변에 감사드립니다 ... 그리고 그들이 실제로 문제를 겪고 있다고 생각하지 않습니다. 그들 중 일부는 스타일링에 관한 것이고 관련이없는 것 같습니다 ... 그리고 다른 사람들은 javascript_include_tag내가 알고있는 ... (분명히 ...) 언급 하지만 Rails 3.1 방식은 모든 것을 마무리하는 것 같습니다. 각 페이지 하단에 개별 자바 스크립트를로드하지 않고 자바 스크립트를 1 개의 파일로로드합니다.

내가 얻을 수있는 가장 좋은 해결책은 특정 기능 divids 또는 classes 로 태그로 묶는 것입니다. 자바 스크립트 코드에서. 그럼 그냥 확인 경우 id또는 class페이지에 있고,이 경우, 당신은 그것과 관련된 자바 스크립트 코드를 실행합니다. 이렇게하면 동적 요소가 페이지에 없으면 application.jsSprockets에 의해 패키지 된 대규모 파일 에 포함되어 있어도 자바 스크립트 코드가 실행되지 않습니다 .

위의 솔루션은 100 페이지 중 8 페이지에 검색 상자가 포함되어 있으면 해당 8 페이지에서만 검색 상자가 실행된다는 이점이 있습니다. 또한 사이트의 8 개 페이지에 동일한 코드를 포함하지 않아도됩니다. 실제로 데이터를 미리로드하는 경우를 제외하고는 사이트에 수동 스크립트 태그를 다시 포함 할 필요가 없습니다.

이것이 내 질문에 대한 실제 답변이라고 생각합니다.


그러나 실제로 수동 <script>태그를 원합니다 . 예, 클래스와 ID는 답변의 일부이지만 사용자가 특정 페이지에 필요하지 않은 JavaScript를로드하는 것은 의미가 없습니다.
Marnen Laibow-Koser 2016 년

4
@ MarnenLaibow-Koser 각 고유 페이지에 수동 스크립트 태그를 추가하지 않는 이유는 모든 페이지보기에서 해당 스크립트 컨텐츠를 다운로드해야하기 때문입니다. 자산 파이프 라인을 사용하여 모든 자바 스크립트를 application.js로 패키징 할 수있는 경우 사용자는 해당 스크립트를 한 번만 다운로드하고 모든 후속 페이지로드시 캐시에서 application.js를 가져옵니다.
jakeonrails

@jakeonrails "각 고유 페이지에 수동 스크립트 태그를 추가하지 않는 이유는 모든 페이지보기에서 해당 스크립트 컨텐츠를 다운로드해야하기 때문입니다." 스크립트는 한 번 다운로드 된 다음 추가 요청에 따라 브라우저 캐시에서 가져옵니다. "자산 파이프 라인을 사용하여 모든 자바 스크립트를 application.js로 패키징 할 수 있으면 사용자는 해당 스크립트를 한 번만 다운로드합니다"-사실이지만 불필요한 코드가 많이 발생합니다. JS를 하나의 큰 파일 대신 여러 개의 작은 파일로 구성 할 수 있으면 불필요한 코드없이 캐싱 이점을 얻을 수 있습니다.
Marnen Laibow-Koser

1
@ MarnenLaibow-Koser 모든 것을 하나의 스크립트로 패키징하면 사용자는 사이트의 모든 페이지에 대해 하나의 스크립트 만 다운로드하면된다고 말하는 것이 좋습니다. 앱의 다른 부분에 대해 여러 개의 스크립트가있는 경우 분명히 사용자가 둘 이상의 스크립트를 다운로드해야합니다. 물론 두 방법 모두 캐싱되지만 대부분의 경우 (중소 규모 응용 프로그램) 하나의 application.js를 한 번만 제공하면 다운로드하는 것이 더 효율적입니다. JS 구문 분석은 제공하는 내용에 따라 다른 이야기가 될 수 있습니다.
jakeonrails

1
@Ziggy 또한 작은 파일이 100 페이지 중 8 페이지에서만 사용된다면 왜 코드가 항상 사용자의 캐시에 있어야합니까? 필요하지 않은 물건을 실제로 버리는 것이 좋습니다.
Marnen Laibow-Koser 2016 년

16

이 파티에 조금 늦게 온다는 것을 알고 있지만 최근에 사용한 솔루션을 사용하고 싶었습니다. 그러나 먼저 언급하겠습니다 ...

The Rails 3.1 / 3.2 Way (아니요, 싫어요)

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

나는이 답변에 완전성을 기하기 위해 다음을 포함시키고 있으며, 그것은 해결책이 아니기 때문에 ...별로 신경 쓰지 않지만.

"Rails Way"는이 질문의 원래 작성자가 요청한대로 뷰 지향적이 아니라 컨트롤러 중심의 솔루션입니다. 해당 컨트롤러의 이름을 딴 컨트롤러 특정 JS 파일이 있습니다. 이러한 모든 파일은 기본적으로 application.js에 지시문이 필요하지 않은 폴더 트리에 배치됩니다.

컨트롤러 별 코드를 포함하기 위해 다음이 뷰에 추가됩니다.

<%= javascript_include_tag params[:controller] %>

나는이 솔루션을 싫어하지만 거기에 있으며 빠릅니다. 아마도 "people-index.js"및 "people-show.js"와 같은 파일을 호출 한 다음 "#{params[:controller]}-index"뷰 지향 솔루션을 얻는 데 사용할 수 있습니다. 다시 말하지만, 빠른 수정이지만 나와 잘 어울리지 않습니다.

내 데이터 속성 방식

미친 짓이라고 부르지 만 배포 할 때 모든 JS를 컴파일하고 application.js로 축소하기를 원합니다. 나는이 작은 꼬마 파일을 모든 곳에 포함시켜야한다는 것을 기억하고 싶지 않습니다.

모든 JS를 하나의 압축 된 브라우저 캐시 파일에로드합니다. 내 application.js의 특정 부분을 페이지에서 실행 해야하는 경우 Rails가 아니라 HTML에서 알려줍니다.

JS를 특정 요소 ID에 잠 그거나 마커 클래스로 HTML을 버리기보다는이라는 사용자 정의 데이터 속성을 사용합니다 data-jstags.

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

각 페이지 에서 DOM을로드 할 때 코드를 실행하기 위해 선호하는 JS 라이브러리 메소드를 여기에 삽입하십시오 . 이 부트 스트랩 코드는 다음 작업을 수행합니다.

  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 함수에 추가 매개 변수를 전달해야하는 경우 창의성을 적용해야합니다. 데이터 매개 변수 속성을 추가하거나 일종의 매개 변수 구문을 찾거나 하이브리드 방식을 사용하십시오.

컨트롤러 고유의 복잡한 워크 플로우가 있더라도 lib 폴더에 파일을 만들고 application.js에 압축하여 'new-thing-wizard'와 같은 태그를 지정하면됩니다. 부트 스트랩이 해당 태그에 도달하면 멋진 멋진 마법사가 인스턴스화되어 실행됩니다. 필요할 때 해당 컨트롤러의보기에 대해 실행되지만 컨트롤러에 연결되지는 않습니다. 실제로 마법사를 올바르게 코딩하면보기에 모든 구성 데이터를 제공 할 수 있으므로 나중에 필요한 다른 컨트롤러에 대해 마법사를 다시 사용할 수 있습니다.

어쨌든, 이것은 지금 당장 페이지 특정 JS를 구현 한 방법이며, 간단한 사이트 디자인과 더 복잡하고 풍부한 응용 프로그램 모두에게 도움이되었습니다. 여기에 제시 한 두 가지 방법 중 하나 인 내 방식이나 Rails 방식 중 하나가 앞으로이 질문을 겪는 사람에게 도움이되기를 바랍니다.


6
한 가지 작은 세부 사항 : js가 브라우저 캐시되면 일단 영향을 미치지 않는다는 대답 에이 개념이 있습니다. 이것은 사실이 아닙니다. js 파일이 올바르게 캐시되면 브라우저는 실제로 다운로드를 피하지만 여전히 모든 페이지 렌더링에서 코드를 컴파일 합니다. 따라서 균형을 유지해야합니다. JS가 많이 있지만 페이지 당 일부만 사용하는 경우 JS를 분리하여 페이지 시간을 향상시킬 수 있습니다.
sujal

내가 말하고있는 컴파일 단계의 실제 효과에 대한 자세한 내용은 pjax가베이스 캠프에 미치는 영향에 대한 37 가지 신호 설명을 참조하십시오. Next : 37signals.com/svn/posts/…
sujal

그것은 좋은 지적입니다. 기사를 읽고 위의 솔루션을 사용한 프로젝트를 되돌아 본 후 기사에서 언급 한 것과 동일한 "변경된 HTML 보내기"솔루션을 작성했음을 알게되었습니다. JS의 빈번한 재 컴파일은 그 때문에 내 프로젝트에서 문제가되지 않았습니다. 컴파일 단계는 덜 "데스크톱 응용 프로그램"지향 사이트에서 작업 할 때 명심해야 할 부분입니다.
Ryan

2
"미치도록 전화하십시오. 그러나 배포 할 때 모든 JS를 컴파일하여 application.js로 축소하기를 원합니다." 사용자가 필요하지 않은 JavaScript를로드하고 핸들러가 거기에 없을 수도있는 속성을 찾도록하므로 실제로는 원하지 않습니다. app.js의 모든 것이 유혹적이며 Rails는 확실히 쉬워 지지만 JavaScript를 더 잘 모듈화하는 것이 올바른 방법입니다.
Marnen Laibow-Koser 2016 년

귀하는 다른 의견을 가질 권리가 있으며 기술적으로는 의견 차이를 무시할 권리가 있습니다. 그러나 하나의 크고 캐시 된 파일이 여러 HTTP 요청을 강제로 모듈화 된 JS를 가져 오는 것보다 열등한 이유에 대한 약간의 정당성을 보는 것이 좋을 것입니다. 또한 처리기 검색 절차와 관련하여 잘못된 것입니다. 태그 값은 검색되지 않습니다. 하나의 검색 만 수행되며 data-jstag 속성이있는 모든 요소를 ​​가져옵니다. 태그 이름으로 검색하지 않고 태그가있는 모든 요소를 ​​찾은 다음 필요한 객체 만 인스턴스화합니다.
Ryan

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레이아웃 파일에서 기존 자바 스크립트 포함 중 도우미 앞에 접두사를 추가하여 새 도우미를 추가하십시오 raw.

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

Voila, 이제 레일의 다른 곳에서 사용하는 것과 동일한 파일 구조를 사용하여보기 별 자바 스크립트를 쉽게 만들 수 있습니다. 파일을 간단하게 붙이십시오 app/assets/:namespace/:controller/action.js.erb!

다른 사람을 돕는 희망!


1
자산이 사전 컴파일 된 후 런타임에 문제가 발생하지 않으며 런타임 <%= raw ... %>에 404?
Nishant

자산 파이프 라인은 종종 사용해서는 안되는 많은 파일을 생성하기 때문에 좋지 않습니다. 따라서 자산 파이프 라인에 의존하는 것은 비효율적 인 시스템에 대한 의존성을 만들고 있습니다.
데보라

1
@DeborahSpeece 자산 파이프 라인은 언제 사용해서는 안되는 파일을 생성합니까? 자산 파이프 라인 (양호)과 require_tree /(나쁨) 을 혼동하고 있습니까?
Marnen Laibow-Koser

6

레이아웃 파일 (예 : application.html.erb)에이 줄을 추가하여 컨트롤러 특정 자바 스크립트 파일 (컨트롤러를 생성 할 때 생성 된 파일)을 자동으로로드 할 수 있습니다.

<%= 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 코드는 하나의 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>사실상 ipso 입니다. 이 페이지의 다른 곳에서 내 의견을 참조하십시오.
Marnen Laibow-Koser 2016 년

이러지 마 여기서 문제는 이들 중 하나를 추가 할 때마다 페이지로드시 실행해야하는 다른 js를 추가한다는 것입니다. 프로젝트가 성장함에 따라 성능이 약간 저하 될 수 있습니다.
ifightcrime

2

JavaScript는 Rails (Sprockets)에게 병합하도록 지시 할 때만 병합됩니다.


물론이야. Rails의 기본값에는 폴더의 모든 것이 포함되어 있기 때문에 묻습니다. David는 당신이 그렇게 할 것을 의미합니다. 그러나 @rubyprince에 대한 다른 의견에서 말했듯이, 이런 식으로 실행될 때 실행이 확실하지 않습니다. 비활성화해야한다고 생각 //= require_tree .합니까?
Fire Emblem

@FireEmblem 예. require_tree .보통 나쁜 생각입니다.
Marnen Laibow-Koser 2016 년

2

이것이 스타일링 문제를 해결하는 방법입니다. (Halm 제외)

%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
마지막 비트를 다시 읽으십시오. 자바 스크립트의 경우 뷰 특정 함수를 초기화하기 위해 스타일 시트에 사용 된 것과 동일한 구조를 활용할 수 있습니다.
zeeraw

필립 $('#post > #edit') ->이 유효하지 않은 것 같습니다. 범위 내에서 작동하도록 jQuery의 범위를 어떻게 지정합니까?
Ramon Tayag

2
최근에 application.html.haml에서 이것을 호출하여 모든 컨트롤러 특정 Java 스크립트 및 스타일 시트를로드하기 시작했습니다. = javascript_include_tag "application"그리고 = javascript_include_tag params[:controller]내가 자바 스크립트 코드를 유지할 수있는이 방법은 파일의 범위 내를 지정할 필요없이 제한.
zeeraw


2

귀하의 답변에 동의하며 해당 선택기가 있는지 확인하려면 다음을 사용하십시오.

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

(아무도 실제 솔루션을 추가하는 것을 보지 못했습니다)


2

나는 그것을 모두 모아서 당신을 위해 그것을 제시하는 대답을 보지 못했습니다. 따라서 Ryan의 답변 의 첫 번째 부분 인 meleyal , sujal (la ClosureCowboy ) 및 Backbone.js에 대한 Gal의 대담한 진술을 짧고 분명하게 정리 하려고 노력할 것입니다. 그리고, 누가 알더라도, 나는 Marnen Laibow-Koser의 요구 사항을 .

편집 예

자산 / 자바 스크립트 / 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 %>


자산 / 자바 스크립트 /foo.js

//= require moment
//= require_tree ./foostuff


자산 / 자바 스크립트 /foostuff/foothis.js.coffee

alert "Hello world!"


간단한 설명

  • application.js//= require_tree . 에서 제거 하고 각 페이지가 공유하는 JS 만 나열하십시오.

  • 위에 application.html.erb에 표시된 두 줄 은 application.js와 페이지 별 JS를 포함 할 위치를 페이지에 알려줍니다.

  • index.html.erb 에서 위에 표시된 세 줄 은 페이지에 특정 JS를 찾고 ": javascript"라는 이름의 yield region (또는 이름을 지정하려는 대상)에 포함 시키도록 뷰에 지시합니다. 이 예제에서 컨트롤러는 "foo"이므로 Rails는 애플리케이션 레이아웃의 : javascript yield region에 "foo.js"를 포함 시키려고 시도합니다.

  • foo.js (또는 컨트롤러 이름)에 페이지 별 JS를 나열하십시오 . 공통 라이브러리, 트리, 디렉토리 등을 나열하십시오.

  • 사용자 정의 페이지 특정 JS를 다른 사용자 정의 JS와 쉽게 구분할 수있는 곳에 보관하십시오. 이 예에서 foo.js에는 foostuff 트리가 필요하므로 foothis.js.coffee와 같은 사용자 정의 JS를 거기에 두십시오 .

  • 여기에는 어려운 규칙이 없습니다. 자유롭게 움직일 수 있으며 필요에 따라 다양한 레이아웃으로 다양한 이름의 여러 수율 영역을 만들 수도 있습니다. 이것은 가능한 첫 걸음 앞으로 보여줍니다. (Backbone.js를 사용한다는 점에서 이와 똑같이 그렇게하지는 않습니다. 또한 foo.js를 foostuff 대신 foo라는 폴더에 놓을 수도 있지만 아직 결정하지 않았습니다.)

노트

CSS를 사용하여 비슷한 작업을 수행 할 수 <%= stylesheet_link_tag params[:controller] %>있지만 이것은 문제의 범위를 벗어납니다.

여기서 눈부신 모범 사례를 놓친 경우 메모를 보내 주시면 적응을 고려하겠습니다. Rails는 나에게 매우 새롭고 솔직히 말해서 엔터프라이즈 개발과 평균 Rails 프로그램이 생성하는 모든 트래픽에 기본적으로 가해지는 혼란에 크게 감명받지 않았습니다.


이것은 갈 길처럼 보입니다. 자세한 답변 덕분에 내 앱에서 구현할 수 있는지 볼 것입니다.
martincarlin87

1

프리미티브가 나에게 잘 작동하지만 멋진 선택적 로딩 전략이 필요하지 않은 또 다른 솔루션이 있습니다. 표준 문서 준비 기능을 넣은 다음 현재 윈도우 위치를 테스트하여 자바 스크립트의 페이지인지 확인하십시오.

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

이것은 여전히 ​​모든 j를 하나의 작은 패키지에 rails 3.x에 의해로드 할 수 있지만 js가 의도하지 않은 페이지와 많은 오버 헤드 또는 충돌을 일으키지 않습니다.


1

ryguy의 대답은 부정적인 점으로 하향 조정되었지만 좋은 대답입니다.

특히 Backbone JS와 같은 것을 사용하는 경우 각 페이지마다 고유 한 Backbone보기가 있습니다. 그런 다음 erb 파일에는 오른쪽 백본보기 클래스를 실행하는 한 줄의 인라인 자바 스크립트가 있습니다. 나는 그것을 한 줄의 '접착제 코드'로 간주하므로 그 인라인이 정상이라는 사실을 생각합니다. 장점은 브라우저가 모든 자바 스크립트를 캐시 할 수 있도록 "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

1

모든 commom JS 파일을 'app / assets / javascript / global'과 같은 하위 폴더로 이동 한 다음 application.js에서 //= require_tree .행을로 수정하십시오 //= require_tree ./global.

이제 컨트롤러 별 JS를 'app / assets / javascript /'루트에 자유롭게 배치 할 수 있으며 컴파일 된 JS에는 포함되지 않으며 = javascript_include_tag컨트롤러 /보기에서 이를 통해 호출 할 때만 사용됩니다 .


어떤 방식으로도 한 페이지에로드 할 수있는 자바 스크립트입니다. 캐시 된 경우에도 중요하지 않습니다.
jackyalcine

1

여기에 몇 가지 답변이 있지만 편집 내용이 가장 좋습니다. Gitlab 에서 얻은 팀에서 사용하는 디자인 패턴 은 디스패처 패턴입니다. 그것은 당신이 말하는 것과 비슷한 것을하지만 페이지 이름은 본문 태그에 레일로 설정됩니다. 예를 들어, 레이아웃 파일에 (HAML에) 다음을 포함하십시오.

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

그런 다음 dispatcher.js.coffeejavascripts 폴더 의 파일에 하나의 클로저와 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

팔로마 프로젝트는 페이지 별 자바 스크립트 코드를 관리하기위한 흥미로운 접근법을 제공합니다.

문서에서 사용 예 :

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

나는 이것을 시도하지 않았지만 다음과 같은 것 같습니다.

  • content_for가 javascript 인 경우 (예 : 실제 javascript가있는) 스프로킷은 그것에 대해 알지 못하므로 현재와 동일한 방식으로 작동합니다.

  • 큰 자바 스크립트 번들에서 파일을 제외하려면 config / sprockets.yml 파일로 이동하여 그에 따라 source_files를 수정하십시오. 그런 다음 필요한 곳에서 제외시킨 파일 만 포함하면됩니다.


그러면 페이지 자체에서 파일을 제외하거나 사용자 정의 자바 스크립트를 사용하는 것이 "올바른 방법"입니까? 다윗이 사람들이 그것을 사용하도록 의도 한 방법입니까?
Fire Emblem

@FireEmblem David가 JavaScript를 올바르게 구성하는 방법을 이해하지 못한다고 생각하기 때문에 David가 의도 한 것을별로 신경 쓰지 않습니다.
Marnen Laibow-Koser 2016 년


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

첫 번째 : \\=require_treeapplication.js에서 제거 두 번째 : 모든 JS 코드를 배치 /app/assets/javascritpt하고 모든 CSS 코드를 배치해야합니다/app/assets/stylesheets


-2

Ryan의 지시에 따라 여기에 내가 한 일이 있습니다.

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

-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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.