the rails present not images asset javascript ruby-on-rails ruby-on-rails-3.1 asset-pipeline sprockets

present - Usando Rails 3.1, ¿dónde coloca su código JavaScript "específico de la página"?



the asset is not present in the asset pipeline (29)

Aprecio todas las respuestas ... y no creo que realmente estén resolviendo el problema. Algunos de ellos tienen que ver con el estilo y no parecen relacionarse ... y otros solo mencionan javascript_include_tag ... lo que sé que existe (obviamente ...), pero parece que la forma en que Rails 3.1 está avanzando es envolver todo de su Javascript en 1 archivo en lugar de cargar Javascript individual al final de cada página.

La mejor solución que se me ocurre es envolver ciertas características en etiquetas div con id o class . En el código javascript. Luego simplemente verifica si el id o la class está en la página, y si lo está, ejecutas el código javascript que está asociado con él. De esta manera, si el elemento dinámico no está en la página, el código javascript no se ejecuta, aunque se haya incluido en el archivo masivo application.js empaquetado por Sprockets.

Mi solución anterior tiene la ventaja de que si se incluye un cuadro de búsqueda en 8 de las 100 páginas, solo se ejecutará en esas 8 páginas. Tampoco tendrá que incluir el mismo código en 8 de las páginas del sitio. De hecho, nunca tendrá que incluir etiquetas de secuencia de comandos manuales en su sitio en ningún lugar nunca más, excepto tal vez para precargar los datos.

Creo que esta es la respuesta real a mi pregunta.

A mi entender, todo su JavaScript se fusiona en 1 archivo. Rails hace esto de forma predeterminada cuando agrega //= require_tree . a la parte inferior de su archivo de manifiesto application.js .

Esto parece un verdadero salvavidas, pero estoy un poco preocupado por el código JavaScript específico de la página. ¿Este código se ejecuta en cada página? Lo último que quiero es que todos mis objetos sean instanciados para cada página cuando solo se necesitan en 1 página.

Además, ¿no hay potencial para el código que choca también?

¿O colocas una pequeña etiqueta de script en la parte inferior de la página que simplemente llama a un método que ejecuta el código javascript para la página?

¿Ya no necesitas require.js entonces?

Gracias

EDITAR : Aprecio todas las respuestas ... y no creo que realmente estén tratando el problema. Algunos de ellos tienen que ver con el estilo y no parecen relacionarse ... y otros solo mencionan javascript_include_tag ... lo que sé que existe (obviamente ...), pero parece que la forma en que Rails 3.1 está avanzando es envolver todo de su JavaScript en 1 archivo en lugar de cargar JavaScript individual al final de cada página.

La mejor solución que se me ocurre es envolver ciertas características en etiquetas div con id o class . En el código JavaScript, simplemente verifica si el id o la class está en la página, y si lo está, ejecutas el código JavaScript que está asociado con él. De esta manera, si el elemento dinámico no está en la página, el código JavaScript no se ejecuta, aunque se haya incluido en el archivo masivo application.js empaquetado por Sprockets.

Mi solución anterior tiene la ventaja de que si se incluye un cuadro de búsqueda en 8 de las 100 páginas, solo se ejecutará en esas 8 páginas. Tampoco tendrá que incluir el mismo código en 8 de las páginas del sitio. De hecho, nunca tendrá que incluir etiquetas de script manuales en su sitio en ningún lugar nunca más.

Creo que esta es la respuesta real a mi pregunta.


Así es como resolví el problema de estilo: (disculpe a Haml)

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

De esta manera comienzo todos los archivos .css.sass específicos de la página con:

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

De esta forma podrás evitar fácilmente cualquier choque. Cuando se trata de archivos .js.coffee , puedes inicializar elementos como;

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

Espero que esto haya ayudado a algunos.


Esto ha sido respondido y aceptado hace mucho tiempo, pero se me ocurrió mi propia solución basada en algunas de estas respuestas y en mi experiencia con Rails 3+.

La cartera de activos es dulce. Utilízalo

Primero, en su archivo application.js , elimine //= require_tree.

Luego, en tu application_controller.rb crea un método auxiliar:

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

Luego, en su archivo de diseño application.html.erb , agregue su nuevo ayudante entre las aplicaciones de JavaScript existentes, con el prefijo del ayudante en raw :

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

Voila, ahora puede crear fácilmente javascript de vista específica utilizando la misma estructura de archivos que usa en todos los demás rieles. Simplemente pegue sus archivos en app/assets/:namespace/:controller/action.js.erb !

Espero que ayude a alguien más!


Estoy de acuerdo con su respuesta, para verificar si ese selector está ahí, use:

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

(No vi a nadie agregar la solución real)


La gema LoadJS es otra opción:

LoadJS proporciona una forma de cargar código Javascript específico de la página en una aplicación de Rails sin perder la magia provista por Sprockets. Todo su código Javascript continuará minificado en un archivo Javascript, pero algunas partes solo se ejecutarán para ciertas páginas.

LoadJS


La respuesta de Felipe es bastante buena. Aquí está el código para que funcione:

En application.html.erb:

<body class="<%=params[:controller].parameterize%>">

Asumiendo que su controlador se llama Proyectos, que generará:

<body class="projects">

Luego en projects.js.coffee:

jQuery -> if $(''body.projects'').length > 0 $(''h1'').click -> alert ''you clicked on an h1 in Projects''


Los JavaScripts solo se combinan cuando le dice a Rails (Sprockets, en lugar de) que los fusione.


Los documentos de Asset Pipeline sugieren cómo hacer JS específico del controlador:

Por ejemplo, si se genera un ProjectsController , habrá un nuevo archivo en app/assets/javascripts/projects.js.coffee y otro en app/assets/stylesheets/projects.css.scss . Debe colocar cualquier JavaScript o CSS exclusivo para un controlador dentro de sus respectivos archivos de activos, ya que estos archivos pueden cargarse solo para estos controladores con líneas como <%= javascript_include_tag params[:controller] %> o <%= stylesheet_link_tag params[:controller] %> .

Enlace a: asset_pipeline


Me doy cuenta de que voy a esta fiesta un poco tarde, pero quería ofrecer una solución que he estado usando últimamente. Sin embargo, permítanme mencionar primero ...

The Rails 3.1 / 3.2 Way (No, señor. No me gusta).

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

Incluyo lo siguiente por el bien de la integridad en esta respuesta, y porque no es una solución inviable ... aunque no me importa mucho.

"Rails Way" es una solución orientada al controlador, en lugar de estar orientada a la vista como el autor original de esta pregunta solicitada. Hay archivos JS específicos del controlador que llevan el nombre de sus respectivos controladores. Todos estos archivos se colocan en un árbol de carpetas que NO se incluye de forma predeterminada en ninguna de las directivas de application.js requieren.

Para incluir un código específico del controlador, se agrega lo siguiente a una vista.

<%= javascript_include_tag params[:controller] %>

Detesto esta solución, pero está ahí y es rápida. Probablemente, en lugar de eso, podría llamar a estos archivos algo como "people-index.js" y "people-show.js" y luego usar algo como "#{params[:controller]}-index" para obtener una solución orientada a la vista. De nuevo, solución rápida, pero no me sienta bien.

Mi forma de atributos de datos

Llámeme loco, pero quiero que TODO mi JS esté compilado y minimizado en application.js cuando lo despliegue. No quiero tener que recordar incluir estos pequeños archivos rezagados en todo el lugar.

Cargo todos mis archivos JS en un archivo compacto, que pronto se guardará en el caché del navegador. Si una determinada parte de mi application.js necesita ser activada en una página, dejo que el HTML me lo diga, no Rails.

En lugar de bloquear mi JS a ID de elementos específicos o ensuciar mi HTML con clases de marcadores, utilizo un atributo de datos personalizado llamado data-jstags .

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

En cada página, uso (inserte el método de biblioteca JS preferido aquí) para ejecutar el código cuando el DOM haya terminado de cargarse. Este código de arranque realiza las siguientes acciones:

  1. Iterar sobre todos los elementos en el DOM marcado con data-jstag
  2. Para cada elemento, divida el valor del atributo en el espacio, creando una matriz de cadenas de etiquetas.
  3. Para cada cadena de etiquetas, realice una búsqueda en un Hash para esa etiqueta.
  4. Si se encuentra una clave coincidente, ejecute la función que está asociada con él, pasando el elemento como un parámetro.

Entonces, digamos que tengo definido lo siguiente en alguna parte de mi 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 };

El evento bootstrapping aplicará las funciones my_autosuggest_init y my_hint_init contra la entrada de búsqueda, convirtiéndola en una entrada que muestra una lista de sugerencias mientras el usuario escribe, además de proporcionar algún tipo de sugerencia de entrada cuando la entrada se deja en blanco y no está enfocada. .

A menos que algún elemento esté etiquetado con data-jstag="auto-suggest" , el código de sugerencia automática nunca se activa. Sin embargo, siempre está ahí, minimizado y, finalmente, almacenado en caché en mi application.js para los momentos en que lo necesito en una página.

Si necesita pasar parámetros adicionales a sus funciones JS etiquetadas, deberá aplicar cierta creatividad. Agregue atributos de parámetros de datos, cree algún tipo de sintaxis de parámetros o incluso utilice un enfoque híbrido.

Incluso si tengo un flujo de trabajo complicado que parece específico del controlador, solo crearé un archivo para él en mi carpeta lib, lo empaquetaré en application.js y lo etiquetaré con algo como ''new-thing-wizard''. Cuando mi bootstrap golpee esa etiqueta, se ejecutará y ejecutará a mi simpático y elegante asistente. Se ejecuta para la (s) vista (s) de ese controlador cuando sea necesario, pero no está acoplado de otra manera al controlador. De hecho, si codifico correctamente el asistente, es posible que pueda proporcionar todos los datos de configuración en las vistas y, por lo tanto, poder reutilizar mi asistente más adelante para cualquier otro controlador que lo necesite.

De todos modos, esta es la forma en la que he estado implementando JS de página específica por un tiempo, y me ha servido bien tanto para diseños de sitios simples como para aplicaciones más complejas / ricas. Esperemos que una de las dos soluciones que he presentado aquí, a mi manera o al estilo de Rails, sea útil para cualquiera que se encuentre con esta pregunta en el futuro.


No veo una respuesta que realmente lo ponga todo junto y lo haga por ti. Por lo tanto, intentaré poner meleyal , sujal (a la ClosureCowboy ), la primera parte de la respuesta de Ryan , e incluso la atrevida declaración de Gal sobre Backbone.js ... todos juntos de una manera que sea breve y clara. Y, quién sabe, podría incluso cumplir con los requisitos de Marnen Laibow-Koser .

Ejemplos de ediciones

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


activos / javascripts / foo.js

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


activos / javascripts / foostuff / foothis.js.coffee

alert "Hello world!"


Breve descripción

  • Eliminar //= require_tree . desde application.js y liste solo los JS que comparte cada página.

  • Las dos líneas que se muestran arriba en application.html.erb indican a la página dónde incluir application.js y su JS específica de la página.

  • Las tres líneas que se muestran arriba en index.html.erb le dicen a su vista que busque un JS específico de la página e lo incluya en una región de rendimiento llamada ": javascript" (o como quiera que lo llame). En este ejemplo, el controlador es "foo", por lo que Rails intentará incluir "foo.js" en la región de rendimiento: javascript en el diseño de la aplicación.

  • Enumere su JS específico de la página en foo.js (o como se llame el controlador). Lista de bibliotecas comunes, un árbol, directorios, lo que sea.

  • Mantenga su JS personalizado de página específica en algún lugar donde pueda hacer referencia fácilmente, aparte de su otro JS personalizado. En este ejemplo, foo.js requiere el árbol foostuff, así que ponga su JS personalizado allí, como foothis.js.coffee .

  • No hay reglas duras aquí. Siéntase libre de mover las cosas y quizás incluso cree múltiples regiones de rendimiento de varios nombres en varios diseños si es necesario. Esto solo muestra un posible primer paso adelante. (No lo hago exactamente así dado nuestro uso de Backbone.js. También podría optar por colocar foo.js en una carpeta llamada foo en lugar de foostuff, pero aún no lo he decidido).

Notas

Puede hacer cosas similares con CSS y <%= stylesheet_link_tag params[:controller] %> pero esto está fuera del alcance de la pregunta.

Si me perdí una práctica deslumbrante, envíeme una nota y seguiré adaptándome. Rails es bastante nuevo para mí y, honestamente, hasta ahora no estoy muy impresionado con el caos que trae por defecto al desarrollo empresarial y todo el tráfico que genera el programa Rails promedio.


Otra opción: para crear archivos específicos de la página o del modelo, puede crear directorios dentro de su carpeta de assets/javascripts/ .

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

Su archivo de manifiesto principal application.js podría configurarse para cargar sus archivos desde global/ . Las páginas específicas o grupos de páginas pueden tener sus propios manifiestos que cargan archivos desde sus propios directorios específicos. Sprockets combinará automáticamente los archivos cargados por application.js con sus archivos específicos de la página, lo que permite que esta solución funcione.

Esta técnica también se puede utilizar para style_sheets/ .


Para los js específicos de la página, puede utilizar la solución Garber-Irish .

Por lo tanto, su carpeta javascripts de Rails podría tener este aspecto para dos controladores: automóviles y usuarios:

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

Y los javascripts se verán así:

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

y markup_based_js_execution contendrá código para el objeto UTIL, y en la ejecución UTIL.init lista para DOM.

Y no olvides poner esto en tu archivo de diseño:

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

También creo que es mejor usar clases en lugar de atributos de data-* , para el mejor css específico de la página. Como mencionó Jason Garber: los selectores de CSS específicos de la página pueden volverse realmente incómodos (cuando usas atributos de data-* )

Espero que esto ayude.


Puede agregar esta línea en su archivo de diseño (por ejemplo, application.html.erb) para cargar automáticamente el archivo javascript específico del controlador (el que se creó cuando generó el controlador):

<%= javascript_include_tag params[:controller] %>

También puede agregar una línea para cargar automáticamente un archivo de secuencia de comandos por acción.

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

Simplemente coloque los scripts de la página en un subdirectorio con el nombre del controlador. En estos archivos podría incluir otros scripts usando = require. Sería bueno crear un ayudante para incluir el archivo solo si existe, para evitar un error 404 en el navegador.


Tal vez encuentre la gema pluggable_js como la solución adecuada.


También puede agrupar los js en carpetas y continuar utilizando la canalización de activos para cargar su javascript de forma selectiva según la página.


Veo que has respondido tu propia pregunta, pero aquí hay otra opción:

Básicamente, estás asumiendo que

//= require_tree .

es requerido. No es. Siéntase libre de eliminarlo. En mi aplicación actual, la primera que hago con 3.1.x honestamente, he creado tres archivos JS de nivel superior diferentes. Mi archivo application.js solo tiene

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

De esta manera, puedo crear subdirectorios, con sus propios archivos JS de nivel superior, que solo incluyen lo que necesito.

Las claves son:

  1. Puede eliminar require_tree - Rails le permite cambiar las suposiciones que hace
  2. No hay nada especial en el nombre application.js : cualquier archivo en el subdirectorio de assets/javascript puede incluir directivas de preprocesador con //=

Espero que ayude y agregue algunos detalles a la respuesta de ClosureCowboy.

Sujal


Paloma proyecto Paloma ofrece un enfoque interesante para administrar el código javascript específico de la página.

Ejemplo de uso de sus documentos:

var UsersController = Paloma.controller(''Users''); // Executes when Rails User#new is executed. UsersController.prototype.new = function(){ alert(''Hello Sexy User!'' ); };


A continuación le indicamos cómo hacerlo, especialmente si no tiene que ejecutar toneladas de bibliotecas para su página específica, sino solo para ejecutar unas pocas cientos de líneas de JS más o menos.

Ya que es perfectamente correcto insertar código Javascript en HTML, simplemente cree en el directorio de aplicaciones / views shared.js y coloque allí el código específico de su página / páginas dentro de my_cool_partial.html.erb

<script type="text/javascript"> <!-- var your_code_goes_here = 0; function etc() { ... } --> </script>

Así que ahora desde donde quieras simplemente haces:

= render :partial => ''shared.js/my_cool_partial''

Y eso es todo, k?


Combiné algunas respuestas en:

Ayudante de aplicación:

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


La respuesta de Ryguy es una buena respuesta, a pesar de que se ha votado a la baja en puntos negativos.

Especialmente si está utilizando algo como Backbone JS: cada página tiene su propia vista Backbone. Luego, el archivo erb solo tiene una sola línea de javascript en línea que activa la clase de vista de la red troncal correcta. Lo considero una sola línea de ''código de pegamento'' y, por lo tanto, el hecho de que esté en línea esté bien. La ventaja es que puede mantener su "require_tree" que le permite al navegador almacenar todo el javascript.

en show.html.erb, tendrás algo como:

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

y en su archivo de diseño, necesitará:

<%= yield :javascript %>


No he probado esto, pero parece que lo siguiente es cierto:

  • si tiene un content_for que es javascript (por ejemplo, con javascript real dentro de él), los piñones no lo sabrían y por lo tanto esto funcionaría de la misma manera que lo hace ahora.

  • si desea excluir un archivo del gran paquete de javascript, debe ingresar en el archivo config / sprockets.yml y modificar los archivos de origen en consecuencia. Luego, solo incluiría cualquiera de los archivos que excluyó donde fue necesario.


Siguiendo el ejemplo de Ryan, esto es lo que he hecho ...

aplicacion.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 (coffeescript específico del controlador, por ejemplo, controller: users, action: dashboard)

window.users_dashboard_onload = () -> alert("controller action called") window.users_onload = () -> alert("controller called")

aplicacion.html.haml

%body{:data=>{:view=>controller.controller_name, :action=>controller.action_name}}


Aunque tiene varias respuestas aquí, creo que su edición es probablemente la mejor opción. Un patrón de diseño que utilizamos en nuestro equipo que obtuvimos de Gitlab es el patrón Dispatcher. Hace algo similar a lo que está hablando, sin embargo, el nombre de la página se establece en la etiqueta del cuerpo mediante rieles. Por ejemplo, en su archivo de diseño, simplemente incluya algo como (en HAML):

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

Luego solo tiene un cierre y una declaración de cambio en su dispatcher.js.coffeearchivo en su carpeta de javascripts, así:

$ -> new Dispatcher() class Dispatcher constructor: -> page = $(''body'').attr(''data-page'') switch page when ''products:index'' new Products() when ''users:login'' new Login()

Todo lo que necesita hacer en los archivos individuales ( por ejemplo, products.js.coffeeo login.js.coffeepor ejemplo) es encerrarlos en una clase y luego globalizar ese símbolo de clase para que pueda acceder a él en el distribuidor:

class Products constructor: -> #do stuff @Products = Products

Gitlab tiene varios ejemplos de esto con los que te puedes meter si tienes curiosidad :)



Mueva todos sus archivos comms JS a una subcarpeta como ''app / asset / javascript / global'' y luego en application.js, modifique la //= require_tree .línea para //= require_tree ./global.

Ahora puede colocar su JS específico del controlador en la raíz ''app / asset / javascript /'' y no se incluirán en el JS compilado, que se usará solo cuando los llame a través = javascript_include_tagde su controlador / vista.


Paso 1. eliminar require_tree. en su application.js y application.css.

Paso 2. Edite su application.html.erb (por defecto de los rieles) en la carpeta de diseño. Agregue "params [: controller]" en las siguientes etiquetas.

<%= stylesheet_link_tag ''application'', params[:controller], media: ''all'', ''data-turbolinks-track'' => true %> <%= javascript_include_tag ''application'', params[:controller], ''data-turbolinks-track'' => true %>

Paso 3. Agregue un archivo en config / initializers / asset.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

referencias: http://theflyingdeveloper.com/controller-specific-assets-with-rails-4/


Primero: elimine //=require_treede application.js Segundo: todo su código JS debe estar asignado /app/assets/javascritpty todo su código CSS debe estar asignado/app/assets/stylesheets


Tengo otra solución, que aunque primitiva funciona bien para mí y no necesita ninguna estrategia de carga selectiva y elegante. Ponga en su nornal función lista de documentos, pero luego pruebe la ubicación actual de Windows para ver si es la página a la que está destinado su javascript:

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

Esto aún permite que todos los js se carguen con rieles 3.x en un paquete pequeño, pero no genera mucha sobrecarga ni conflictos con las páginas para las que no está diseñado el js.


<%= javascript_include_tag params[:controller] %>