A melhor maneira de adicionar JavaScript específico da página em um aplicativo Rails 3?

159

O Rails 3 possui um JavaScript discreto, o que é bem legal.

Mas eu queria saber qual é a melhor maneira de incluir JavaScript adicional para uma página específica.

Por exemplo, onde eu poderia ter feito anteriormente:

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

Agora podemos torná-lo discreto com algo como

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

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

Acho que minha pergunta é onde / como incluir esse JavaScript? Não quero preencher o application.jsarquivo porque esse JavaScript é aplicável apenas a essa visualização. Devo incluir um arquivo JavaScript personalizado para cada página de alguma forma ou colá-lo em uma variável de instância que o cabeçalho procura?

Brian Armstrong
fonte
Para aqueles que desejam um entendimento completo de como isso funciona e o que é melhor, leia railsapps.github.io/rails-javascript-include-external.html . Essa é de longe a melhor documentação que eu já vi sobre esse tópico. É uma ótima leitura, não apenas para o Rails, mas para qualquer pessoa que lide com desenvolvedores da web. É por isso que é melhor fazer as coisas da maneira certa. Certamente usarei o Unholy Rails para minhas futuras perguntas. UAU.
precisa saber é o seguinte
2
@KateGregory que um é mais novo.
Ciro Santilli escreveu

Respostas:

153

O que eu gosto de fazer é incluir o Javascript por visualização em um content_for :headbloco e, em seguida, yieldnesse bloco no layout do aplicativo. Por exemplo

Se for bem curto, então:

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

ou, se mais tempo, então:

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

Então, no seu arquivo de layout

<head>
  ...
  <%= yield :head %>
</head>
bjg
fonte
40
Por que não usar o <%= javascript_include_tag "my_javascipt_file" %> ?
AJP
5
@AJP eu acho, então ele derrota o propósito de gasoduto de ativos
lulalala
2
@lulalala, mas o código na resposta não faz isso de qualquer maneira, mas de uma maneira mais confusa?
AJP
8
O @AJP é mais confuso, mas tem uma solicitação HTTP a menos que sua resposta.
lulalala
103

Se você deseja incluir o javascript apenas em uma página, é possível incluí-lo na página, é claro, no entanto, se você deseja agrupar o seu javascript e tirar proveito do pipeline de ativos, js minificados etc., é possível fazê-lo e ter mais Recursos js que são combinados e carregados apenas em páginas específicas, dividindo seus js em grupos que se aplicam apenas a determinados controladores / visualizações / seções do site.

Mova seus js em ativos para pastas, com um arquivo de manifesto separado para cada um; portanto, se você tiver uma biblioteca js de administrador usada apenas no back-end, faça o seguinte:

  • ativos
    • javascripts
      • admin
        • ... js
      • admin.js (manifesto para o grupo de administradores)
      • application.js (manifesto para o grupo global de aplicativos)
      • global
        • ... js

no application.js existente

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

em um novo arquivo de manifesto admin.js.

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

Certifique-se de que este novo manifesto js seja carregado editando config / production.rb

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

Em seguida, ajuste o layout da página para incluir js extras no cabeçalho da página:

<%= content_for :header %>   

Em seguida, nas visualizações em que você deseja incluir esse grupo js específico (assim como o grupo de aplicativos normal) e / ou qualquer js, css etc. específico da página:

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

É claro que você pode fazer o mesmo com o css e agrupá-lo de maneira semelhante para aplicar apenas em determinadas áreas do site.

Kenny Grant
fonte
Se você mantiver todos os seus manifestos no mesmo local, poderá pedir aos trilhos para pré-compilar tudo nessa pasta. Dessa forma, você só precisa editar o production.rb uma vez e não acompanhar o que adicionou a ele.
Undistraction
Você não sabia que podia fazer isso - para ter uma pasta 'manifestos' que continha seus manifestos, bem como os grupos js individuais? Eu posso tentar isso. Eu gostaria que eles tivessem uma configuração um pouco mais sã por padrão, pois parece que eles pressupõem que você apenas jogará todos os js em um grande arquivo importado em qualquer lugar.
Kenny Grant
estranho, eu recebo um erro Sprockets :: FileNotFound se eu usar //= require_tree ./global, mas não se eu usar o //= require_directory ./globalRails 3.2.12.
Qix 8/13
2
Parece que você terminará com muitas tags de script. Eu pensei que o objetivo do pipeline de ativos era ter apenas uma tag de script? Gostaria apenas de escrever os javascripts para que sejam específicos da página.
Ziggy
1
Eu acho que entendi. Evitar tags de script adicionais é muito importante para o tempo de carregamento da página.
Ziggy
12

Essas respostas me ajudaram muito! Se alguém quiser um pouco mais ...

  1. Você precisa colocar javascripts em manifestos se desejar pré-compilados. No entanto, se você precisar de todos os arquivos javascript application.js.coffee, todos os javacsripts serão carregados toda vez que você navegar para uma página diferente, e o objetivo de executar javascripts específicos da página será derrotado.

Portanto, você precisa criar seu próprio arquivo de manifesto (por exemplo speciifc.js) que exigirá todos os arquivos javascript específicos da página. Além disso, modifique require_treedeapplication.js

app / assets / javascripts / application.js

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

app / assets / javascripts / specific.js

//= require_tree ./specific

Em seguida, environments/production.rbadicione seu manifesto à lista pré-compilada com a opção de configuração,

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

Feito! Todos os javascripts compartilhados que sempre devem ser carregados serão colocados na app/assets/javascripts/globalpasta e os javascripts específicos da página emapp/assets/javascripts/specific . Você pode simplesmente chamar os javascripts específicos da página na exibição, como

<%= javascript_include_tag "specific/whatever.js" %> //.js é opcional.

Isso é suficiente, mas eu também queria usá javascript_include_tag params[:controller]-lo. Quando você cria controladores, um arquivo de café associado é gerado app/assets/javascriptscomo as outras pessoas mencionadas. Existem javascripts verdadeiramente específicos do controlador , que são carregados apenas quando o usuário atinge a visualização específica do controlador.

Então eu criei outro manifesto controller-specific.js

app / assets / javascripts / controller-specific.js

//= require_directory .

Isso incluirá todos os scripts de café gerados automaticamente associados aos controladores. Além disso, você precisa adicioná-lo à lista pré-compilada.

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

Maximus S
fonte
Muito obrigado pela resposta detalhada. Onde devo colocar essa linha javascript_include_tag params[:controller]. Atualmente meu application.html.erb tem esta linha javascript_include_tag 'application'. Devo substituir isso pela outra linha?
21413 Simha
1
Além disso, devo colocar esta linha <%= javascript_include_tag "specific/whatever.js" %>em um content_for :headerbloco?
21413 Simha
1
É estranho para mim que você precise mexer config.assets.precompile. Tudo não é app/assets/javascripts/*.jspré-compilado automaticamente?
AlexChaffee
@AlexChaffee Somente os arquivos disponíveis são automaticamente application.csse application.js. Outros devem ser incluídos em outros arquivos ou listados usando config.assets.precompile. Leia mais aqui
Sung Cho
A declaração do manifesto foi movida. Estou executando os trilhos 4.2.0. e encontrou este comentário no arquivo production.rb: # config.assets.precompilee config.assets.versionfoi movido para config / initializers / assets.rb
curt
11

Eu prefiro o seguinte ...

No seu arquivo application_helper.rb

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

e depois em sua visão específica (app / views / books / index.html.erb neste exemplo)

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

... Parece funcionar para mim.

Cailinanne
fonte
9

Se você não deseja usar o pipeline de ativos ou as soluções complexas para obter o javascript específico da página necessário (eu simpatizo), a maneira mais simples e robusta, que obtém o mesmo que as respostas acima, mas com menos código, é apenas para: usar:

<%= javascript_include_tag "my_javascipt_file" %>

Nota: isso requer mais uma solicitação http por tag de inclusão do que as respostas que usam content_for :head

AJP
fonte
javascript_include_tagfoi exatamente o que eu estava procurando, aplausos AJP
Tom McKenzie
onde você coloca "my_javascipt_file"? Em recursos / javascripts? Mas, se sim, isso não seria detectado automaticamente com um //= require .no application.js?
Qix 8/13
@ Linus sim, //= require .traria esse script para qualquer página do seu site, assim você teria que fazer algo como Kenny Grant (uso //= require_tree ./global) ou bjg sugerido.
AJP
1
Esse foi de longe o método mais fácil para mim, mudei //= require_tree .para //= require_directory .em application.js e criei um subdiretório em assets \ javascripts. Observe que você precisa incluir o novo diretório em config \ initializers \ assets.rb para pré-compilar seus js adicionando a linha:Rails.application.config.assets.precompile += %w( new_dir/js_file.js )
Jonesy
7

Dê uma olhada na jóia pluggable_js . Você pode achar esta solução mais fácil de usar.

peresleguine
fonte
3

Meu entendimento é que o pipeline de ativos visa diminuir o tempo de carregamento da página, combinando todos os seus js juntos em um arquivo (minificado). Embora isso possa parecer repugnante na superfície, é realmente um recurso que já existe em idiomas populares como C e Ruby. Coisas como tags "include" têm como objetivo impedir a inclusão múltipla de um arquivo e ajudar os programadores a organizar seu código. Quando você escreve e compila um programa em C, todo esse código está presente em todas as partes do seu programa em execução, mas os métodos só são carregados na memória quando esse código está sendo usado. Em certo sentido, um programa compilado não inclui nada para garantir que o código seja bem modular. Tornamos o código modular, escrevendo nossos programas dessa maneira, e o sistema operacional apenas carrega na memória os objetos e métodos necessários para uma determinada localidade. Existe algo como "inclusão específica de método"? Se o seu aplicativo Rails for tranquilo, é isso que você está pedindo.

Se você escrever seu javascript para aumentar o comportamento dos elementos HTML na página, essas funções serão "específicas da página" por design. Se houver algum código complicado que você tenha escrito de tal forma que seja executado independentemente do seu contexto, considere vincular esse código a um elemento html de qualquer maneira (você pode usar a tag body, conforme descrito no método Garber-Irish ). Se uma função for executada condicionalmente, o desempenho provavelmente será menor do que todas essas tags de script extras.

Estou pensando em usar a paloma gem, conforme descrito no projeto de aplicativos rails . Em seguida, você pode tornar sua página javascript específica, incluindo funções específicas da página em um retorno de chamada paloma:

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

Você usa trilhos, então eu sei que você ama gemas :)

Ziggy
fonte
3

Você não deve carregar seus arquivos JS ou CSS fora do pipeline de ativos, pois perde recursos importantes que tornam o Rails tão bom. E você não precisa de outra jóia. Eu acredito em usar o mínimo possível de gemas, e usar uma gema não é necessário aqui.

O que você deseja é conhecido como "Javascript Específico do Controlador" ("Javascript Específico da Ação está incluído na parte inferior). Isso permite que você carregue um arquivo JavaScript específico para um CONTROLADOR específico. Tentar conectar seu Javascript a uma Visualização é uma espécie de .." Você deseja associá-lo aos seus Controladores ou ações dentro dos seus Controladores.

Infelizmente, por qualquer motivo, os desenvolvedores do Rails decidiram que, por padrão, todas as páginas carregam todos os arquivos JS localizados no diretório de ativos. Por que eles decidiram fazer isso em vez de ativar o "Javascript específico do controlador" por padrão, nunca saberei. Isso é feito através do arquivo application.js, que inclui a seguinte linha de código por padrão:

//= require_tree .

Isso é conhecido como diretiva . É o que os sprockets usam para carregar todos os arquivos JS no diretório assets / javascripts. Por padrão, os sprockets carregam automaticamente application.js e application.css, e a diretiva require_tree carrega todos os arquivos JS e Coffee em seus respectivos diretórios.

NOTA: Quando você andaimes (se não estiver andando agora, é um bom momento para começar), o Rails gera automaticamente um arquivo de café para você, para o controlador desse andaime. Se você deseja gerar um arquivo JS padrão em vez de um arquivo de café , remova a gema de café que está ativada por padrão no seu Gemfile e seu andaime criará arquivos JS.

Ok, o primeiro passo para ativar o "Javascript específico do controlador" é remover o código require_tree do seu arquivo application.js OU alterá-lo para uma pasta no diretório assets / javascripts, se você ainda precisar de arquivos JS globais. IE:

//= require_tree ./global

Etapa 2: vá para o arquivo config / initializers / assets.rb e adicione o seguinte:

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

Insira os nomes do controlador que você deseja.

Etapa 3: Substitua o javascript_include_tag no arquivo application.html.erb por este (observe a parte params [: controller]:

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

Reinicie seu servidor e viola! O arquivo JS que foi gerado com o seu andaime agora será carregado somente quando esse controlador for chamado.

Precisa carregar um arquivo JS específico em uma ACTION específica no seu controlador , IE / articles / new ? Faça isso:

application.html.erb :

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

config / inicializadores / assets.rb :

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

Em seguida, inclua uma nova pasta com o mesmo nome que você controla na pasta assets / javascripts e coloque seu arquivo js com o mesmo nome da sua ação. Em seguida, ele será carregado nessa ação específica.

Erick Maynard
fonte
1

Ok, talvez isso seja o pior trabalho de todos os tempos, mas eu crio um método de controlador que acabou de renderizar o arquivo .js

Controlador

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

Visão

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

se por algum motivo não quisermos fazer isso, entre em contato.

Conta
fonte
1

A maneira preferida de adicionar JS está no rodapé, para que você possa fazer o seguinte:

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 %>
Syed
fonte