改进 Rails 应用程序中不显眼的 javascript(并且可能使用 CoffeeScript)
我有一个应用程序,它使用一些 Javascript 来执行基本的 Ajax 请求,例如自动完成和实时搜索。例如,我通过以下方式实现了实时搜索;我发现了一些潜在的问题,想与您讨论一下,以便有更好的代码。
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);
以下是让我对代码的最优性产生怀疑的事情:
- 我在
_livesearch_box.html.haml
。 - 即使我将其放入
public/javascripts/companies_livesearch.js
中,我也必须对其中的#search
部分进行硬编码。 - 我在
public/javascripts/companies.js
中硬编码了#company_list_container
(这是渲染_companies.html.haml
的 div)。 - 我在
public/javascript/companies.js
中硬编码了路径/companies/liveseach?query=
。 - 我没有使用 CoffeeScript,主要是因为它期望(至少如果您使用 Barista)在某个地方找到纯 javascript 代码(例如在
app/coffeescripts/
中)并将其编译到public/javascripts 中
。但在我的应用程序中,我的app/views/companies
中也有一些.js.erb
文件;例如,我有一个投票系统,它使用以下内容 app/views/companies/_vote.js.erb:$("#vote_link_<%= escape_javascript(@company.id.to_s) %>").html("<%= escape_javascript(vote_link_for(@company)) %>")
使用 Ajax 请求将“投票该公司”链接替换为“取消投票该公司”链接(反之亦然),并由vote
和unvote
操作呈现在控制器中。 我知道有 Coffee-haml-filter 可以在 haml 文件中编译 CoffeeScript,但这不是我真正需要的,并且通常被弃用并被视为肮脏的东西(?)。
所以问题至少是:
- 如何在我的
app/views/*/*.js.*
中使用 CoffeeScript? - 我应该有
app/views/*/*.js.*
文件吗? - 如何以最有效和优雅的方式删除所有这些元素 ID 和硬编码在 JavaScript 中的路径?
抱歉问了这么长的问题,感谢您看完它!
I have an application which uses some Javascript for basic Ajax requests such as autocompletion and live search. For example I implemented live search in the following way; I spotted some potential issue and would like to talk with you about it, so to have a better code.
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);
Here are the things that make me suspicious about the optimality of my code:
- I have Javascript code in
_livesearch_box.html.haml
. - Even if I put it in a
public/javascripts/companies_livesearch.js
I would have to hardcode the#search
part in it. - I have
#company_list_container
(which is the div in which_companies.html.haml
is rendered) hardcoded inpublic/javascripts/companies.js
. - I have the path
/companies/liveseach?query=
hardcoded inpublic/javascript/companies.js
. - I'm not using CoffeeScript, mainly because it expects (at least if you use Barista) to find pure javascript code somewhere (e.g. in
app/coffeescripts/
) and compiles it inpublic/javascripts
. But in my application I also have some.js.erb
file in myapp/views/companies
; for example, I have a voting system that uses the following in
app/views/companies/_vote.js.erb:$("#vote_link_<%= escape_javascript(@company.id.to_s) %>").html("<%= escape_javascript(vote_link_for(@company)) %>")
To replace the "Vote this company" link with the "Unvote this company" one (and vice-versa) with an Ajax request and is rendered by thevote
andunvote
actions in the controller.
I know that there is coffee-haml-filter that compiles CoffeeScript inside haml files but it's not what I exactly need and is usually deprecated and regarded as something dirty (?).
So the questions are at least:
- How to have CoffeeScript in my
app/views/*/*.js.*
? - Should I have
app/views/*/*.js.*
files at all? - How to remove all those element ids and those paths hardcoded in javascripts in the most efficient and elegant way?
Sorry for the long question and thanks for getting to the end of it!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
路线
有一些解决方案,例如 js-routes (我的叉子),它允许您编写
Router.post_path(3)
在你的 JS/CS 中。这样你就可以绕过硬编码 url。混合 JS 和 ERB
我建议您避免混合 JS 和 Ruby。在大多数情况下,您可以通过重构 JS 代码来解决这个问题,结果将更易于阅读,并且可以简单地移动到纯 JS/CS 文件中。
除非你做了邪恶的 eval-magic,否则你甚至不需要
escape_javascript
。但你必须从你的部分中删除 JavaScript。jquery.livequery
使转换变得更加容易。每次将
.company
插入文档时都会被调用。硬编码 DOM 路径
如果您正在为特定的 dom 树(或特定的视图)编写代码,我不认为这是一个坏习惯。编写不显眼的 JS 就像编写 CSS - 我们也在 CSS 中硬编码
#company_list_container
,不是吗?从前端调用 JS 代码
为了在静态 CoffeeScript 文件和视图之间建立一个接口,我倾向于
在视图末尾编写如下内容:然后,这将调用我用 CoffeeScript 编写的函数,该函数将使用所有需要的脚本增强站点。可能有更好的方法(比如有一个类似 Rails 的 JavaScript 路由器 - 请参阅 Backbone.js),但它很简单并且适合我。
另外,如果我经常需要一些数据(例如:current_user):
但是我认为没有一种有效的重构方法。我必须进行大量重构才能消除 ERB/JS 混乱。不过还是值得的。
Routes
There are some solutions like js-routes (my fork) which will allow you to write
Router.post_path(3)
in your JS/CS. This way you can get around hardcoding urls.Mixing JS and ERB
I would advise you to avoid mixing JS and Ruby. In most cases you can get around that by refactoring your JS code, the result will be easier to read and can simply be moved into a pure JS/CS-file.
Unless you do evil eval-magic, you won't even need
escape_javascript
. But you will have to remove the JavaScript from inside your partials.jquery.livequery
made the transition easier.will be called each time a
.company
is inserted into the document.Hardcoding DOM-Paths
If you are writing code for a specific dom-tree (or a specifc view) I wouldn't consider it a bad practice. Writing unobtrusive JS is like writing CSS - and we hardcode
#company_list_container
in CSS too, don't we?Calling the JS code from the frontend
To have an interface between the static CoffeeScript-files and the views I tend to write something like:
at the end of my views. This will then call a function I wrote with CoffeeScript, which will then enhance the site with all the needed scripts. There might be better approaches (like having a Rails-like Router for JavaScript - see Backbone.js) but it's simple and works for me.
Also if I need some data quite often (for example: the current_user):
However I don't think there is an efficient way to refactor. I had to do a lot of refactoring to get my ERB/JS mess removed. Still worth, though.