example - Mejore la javascript discreta(y posiblemente use CoffeeScript) en una aplicación de Rails
ruby on rails ajax example (1)
Tengo una aplicación que usa Javascript para solicitudes básicas de Ajax, como autocompletado y búsqueda en vivo. Por ejemplo, implementé la búsqueda en vivo de la siguiente manera; Descubrí un problema potencial y me gustaría hablar con usted sobre eso, para tener un mejor código.
app / controllers / company_controller.rb
def livesearch
@companies = Company.search(params[:query])
render :partial => "companies", :locals => {:companies => @companies}
end
app / views / companies / _companies.html.haml
- if companies.empty?
None
- else
%table#company_list
%tr
%th Name
%th Description
%th Products
%th
= render companies
app / views / companies / _livesearch_box.html.haml
= content_for :scripts, "jlivesearch companies"
= form_tag "#", :autocomplete => :off, :remote => true do
%span.light
Search:
= text_field_tag :search
:javascript
$(''#search'').livesearch({
searchCallback: update_listed_companies,
queryDelay: 200,
innerText: "Search companies"
});
public / javascripts / companies.js
function update_listed_companies(query) {
if(typeof query == "undefined")
query = "";
$("#company_list_container").showWith(
"/companies/livesearch?query=" + query,
false
);
}
public / javascripts / application.js
(function($) {
$.fn.showWith = function (what, popup) {
element = this;
$.get(what, function(data) {
element.html(data);
if(popup)
element.bPopup();
});
return element;
};
})(jQuery);
Aquí están las cosas que me hacen sospechar sobre la optimalidad de mi código:
- Tengo un código Javascript en
_livesearch_box.html.haml
. - Incluso si lo coloco en un
public/javascripts/companies_livesearch.js
tendré que codificar la parte#search
en él. - Tengo
#company_list_container
(que es el div en el que se_companies.html.haml
) hardcoded enpublic/javascripts/companies.js
. - Tengo la ruta
/companies/liveseach?query=
hardcoded enpublic/javascript/companies.js
. - No estoy usando CoffeeScript, principalmente porque espera (al menos si usa Barista) buscar el código JavaScript puro en alguna parte (por ejemplo, en
app/coffeescripts/
) y lo compila enpublic/javascripts
. Pero en mi aplicación también tengo algún archivo.js.erb
en miapp/views/companies
; por ejemplo, tengo un sistema de votación que usa lo siguiente en app / views / companies / _vote.js.erb :$("#vote_link_<%= escape_javascript(@company.id.to_s) %>").html("<%= escape_javascript(vote_link_for(@company)) %>")
Reemplazar el enlace" Vote this company "con" Unvote this company "(" No invitar a esta empresa ") con una solicitud de Ajax y se rinde con elvote
y lavote
unvote
acciones en el controlador. Sé que hay coffee-haml-filter que compila CoffeeScript dentro de los archivos haml, pero no es exactamente lo que necesito y generalmente está en desuso y se considera algo sucio (?).
Entonces las preguntas son al menos:
- ¿Cómo tengo CoffeeScript en mi
app/views/*/*.js.*
? - ¿Debo tener archivos
app/views/*/*.js.*
? - ¿Cómo eliminar todos los identificadores de elementos y esas rutas codificadas en javascripts de la manera más eficiente y elegante?
Perdón por la larga pregunta y gracias por llegar al final!
Rutas
Hay algunas soluciones como js-routes (mi fork) que te permitirán escribir Router.post_path(3)
en tu JS / CS. De esta forma puede evitar urls de codificación rígida.
Mezcla de JS y ERB
Te aconsejo que evites mezclar JS y Ruby. En la mayoría de los casos puede solucionarlo refacturando su código JS, el resultado será más fácil de leer y simplemente se puede mover a un archivo JS / CS puro.
# based on your vote-link example and assuming that your link
# looks like:
#
# %a(href="#"){:"data-company-id" => @company.id} Vote
# => <a href="#" data-company-id="6">Vote</a>
makeAllCompaniesVotable: () ->
$(''.company a.voteLink'').click ->
companyId = $(this).data(''company-id'')
$.ajax
url: Router.vote_company_path(companyId)
# ...
A menos que hagas evil eval-magic, ni siquiera necesitarás escape_javascript
. Pero deberá eliminar el JavaScript de sus parciales. jquery.livequery
hizo la transición más fácil.
$(`.company`).livequery ->
# do something with $(this)
se llamará cada vez que se inserte una .company
en el documento.
Hardcoding DOM-Paths
Si está escribiendo código para un dom-tree específico (o una vista específica), no lo consideraría una mala práctica. Escribir JS discreto es como escribir CSS, y también codificamos #company_list_container
en CSS, ¿no?
$("#vote_link_<%= escape_javascript(@company.id.to_s) %>") # this is ugly though
Llamar al código JS desde la interfaz
Para tener una interfaz entre los archivos estáticos de CoffeeScript y las vistas, tiendo a escribir algo como:
:javascript
$(function(){Companies.index()});
$(function(){Application.globalEnhancements()});
al final de mis puntos de vista. Esto llamará a una función que escribí con CoffeeScript, que luego mejorará el sitio con todos los scripts necesarios. Puede haber mejores enfoques (como tener un enrutador tipo Rails para JavaScript, ver Backbone.js) pero es simple y funciona para mí.
Además, si necesito algunos datos con bastante frecuencia (por ejemplo: el usuario actual):
:javascript
window.current_user = #{current_user.to_json};
Sin embargo, no creo que haya una forma eficiente de refactorizar. Tuve que hacer muchas refacciones para eliminar mi ERB / JS mess. Todavía vale la pena, sin embargo.