如何从 JS ERB 内部执行辅助方法?
Posted
技术标签:
【中文标题】如何从 JS ERB 内部执行辅助方法?【英文标题】:How do I execute a helper method from inside a JS ERB? 【发布时间】:2015-10-04 04:13:50 【问题描述】:我的dashboard_helper.rb
中有一个辅助方法,如下所示:
def show_number_of_comments(node)
if node.comments_count == 1
"#node.comments_count Comment"
else
"#node.comments_count Comments"
end
end
在我的常规dashboard#index
视图中,我这样称呼它:
<h4 class="card-comments-title"><%= show_number_of_comments(node) %></h4>
但我想在添加新评论时通过 AJAX 更新呈现的元素,所以在我的comment#create.js.erb
中,我想引用那个辅助方法,但是当我尝试这个时,它不起作用:
$('#<%= @card_id %> .card-comments-title').html('<%= show_number_of_comments(@node) %>');
但是当我这样做时,它会起作用:
$('#<%= @card_id %> .card-comments-title').html('<%= @comment_count %> Comments');
后者的问题是它不能处理复数。
解决这个问题的最佳方法是什么?
编辑 1
当我说它不起作用时,我的意思是:
NoMethodError at /nodes/5/comments
==================================
> undefined method `show_number_of_comments' for #<#<Class:0x007fbd3715e5b8>:0x007fbd3715d4d8>
app/views/comments/create.js.erb, line 5
----------------------------------------
另外,@node
对象在我的Comments#Create
中声明如下:
def create
@node = Node.find(params[:node_id])
@comment = current_user.comments.new(comment_params)
@comment.node = @node
@card_id = params[:card_id]
@comment_count = @node.comments_count + 1
current_user.events.create(action: "commented", eventable: @comment)
binding.pry
respond_to do |format|
if @comment.save and @node.save
format.js
else
format.js
end
end
end
当我如上所述通过binding.pry
停止执行并尝试执行@node
时,我得到了我期望的值:
[1] pry(#<CommentsController>)> @node
=> #<Node id: 5, name: "Reverse Crunches", family_tree_id: 1, user_id: 1, media_id: 5, media_type: "Video", created_at: "2015-07-25 05:49:51", updated_at: "2015-07-25 21:05:34", circa: nil, is_comment: nil, cached_votes_total: 0, cached_votes_score: 0, cached_votes_up: 0, cached_votes_down: 0, cached_weighted_score: 0, cached_weighted_total: 0, cached_weighted_average: 0.0, cached_user_tag_list: nil, cached_num_user_tags: 0, cached_tagged_user_names: [], comments_count: 3>
编辑 2
有时它只是失败了。它不会向控制台或我的服务器日志输出任何错误,它只是将.card-comments-title
替换为空白值。
【问题讨论】:
纯 JS 方法为您提供了脱离表示的逻辑解耦,您尝试过了吗? “它不起作用”到底是什么意思?您是否收到未定义的方法错误? 在 HTML 视图中,使用node
调用辅助方法,在 JS 中使用 @node
调用它。
【参考方案1】:
所以我想出了在我的具体情况下我想做什么,即在我的 JS ERB 中复数评论计数,但我还没有想出如何在我的 JS ERB 中使用helper_method
- 所以这个答案没有真的不回答这个问题。
但是,我在此处记录这一点,以防其他人遇到类似问题并且我的解决方案可以帮助他们。
在我的 JS ERB 中,我所做的只是使用 Rails 方法pluralize。我完全忘记了它,直到我输入了这个问题,它就像一个魅力。
这是我的create.js.erb
的代码 sn-p:
$('#<%= @card_id %> .card-comments-title').html('<%= pluralize(@comment_count, "Comment") %>');
就像一个魅力,但这仍然不能回答我关于在此处引用/使用辅助方法的问题。
【讨论】:
我不确定这是否得到回答。只是想回答,因为现在我很好奇,因为我的助手在 js.erb 中为我工作。我认为您的 @node 不能在您的 create.js.erb 文件中可用,这就是它不适合您的原因。即使你调用了复数,复数仍然是一个被调用的辅助方法。如果您的“@node”不存在,node.cmets_count 一定是崩溃了。 是的,绝对可以在 erb 中调用助手,不管它是js
还是 html
。我认为与@Athar 相同:@node
很可能为零。
@Athar 我相信你可能有正确的答案。写下来作为答案,我会接受的。你是对的,因为pluralize
确实有效(这是一个 Rails 助手)。
@Athar 所以我测试了你的想法,结果证明@node
实际上设置正确。我用更多调试细节更新了问题。
以及问题仍然存在,我没有发布答案。我想到的第二种情况是它无法从 cmets#create.js.erb 调用 dashboard_helper 方法,尽管这应该是不可能的,但不幸的是我无法复制它。如果我是你,我会先尝试将此方法移至comments_helper
或application_helper
并调用,以确认问题出在方法或帮助文件上。?如果方法从那里开始工作,那么问题出在仪表板帮助文件上。这个文件在哪里。? app/helpers/dashboard_helper
.?【参考方案2】:
如果不需要本地化,您也可以尽量避免使用后端:
var comentsNumber = function(num)
return (num == 0 || num > 1) ? num + " Comments" : num + " Comment"
;
var domObject = $('#<%= @card_id %> .card-comments-title');
基本上您可以通过 AJAX 调用轻松更新对象并触发内容重新加载:
var htmlContent = comentsNumber(<%= @comment_count %>);
domObject.html(htmlContent);
【讨论】:
这是一种有趣的方法,但并不能完全回答我想知道的内容:辅助方法。【参考方案3】:显示单数/复数文本可能更好的解决方案是通过 i18n。您可以尝试以下方法:
# config/locales/en.yml
en:
comments:
zero: No comments
one: 1 comment
other: %count comments
那么在您看来,您可以将其用作:
$('#<%= @card_id %> .card-comments-title').html("<%= t('comments', count: @node.comments_count) %>");
关于助手不工作的问题:鉴于您在app/helpers/
目录中有dashboard_helper.rb
,您的助手应该可以工作。对于您描述的问题,以下行在哪里起作用:
$('#<%= @card_id %> .card-comments-title').html('<%= @comment_count %> Comments');
以下不是:
$('#<%= @card_id %> .card-comments-title').html('<%= show_number_of_comments(@node) %>');
如果您有show_number_of_comments(@node)
的输出,或许使用console.log
,您可能会找到更好的答案。很可能需要使用escape_javascript
转义此输出。所以,虽然不是一个具体的解决方案,但我建议你尝试一下:
$('#<%= @card_id %> .card-comments-title').html('<%= j show_number_of_comments(@node) %>');
【讨论】:
我尝试用escape_javascript
逃避它,但没有骰子。
另外,实现这一点的更好方法是使用 Rails 辅助方法pluralize
,我相信它使用 I18n。当我尝试执行console.log("@Node is: <%= j show_number_of_comments(@node) %>");
时会打印出:@Node is: 8 Comments
其中8
是我提交最后一个之前的cmets 数,所以理论上应该吐出...9 Comments
而不是8
。
i18n added pluralize
尚未发布!它只在master branch 上,不在4.2 stable 上。您期望的下一个理论行为不会发生,因为您之前已经查询过@node
。如果您使用查询重新分配@node
,您将获得9 Comments
。
阅读您的编辑后,我建议您通过@node
而不是通过current_user
构建comment
。所以,@node.comments.new(comment_params)
并分配 current_user
给它。这将允许您使用 @node.comments.length
而不是额外的变量 @comment_count
。
请记住,无论如何我都必须增加 cmets 计数,而 @node.comments_count
直接来自列,而不是 ruby 方法 - 所以我不确定这个建议会更有效。即问题是,当comment_count
是counter_cache
时,@node.comments.length
是否比@node.comment_count
更有效?我对此表示怀疑。【参考方案4】:
编辑:对于 Rails 3.1+,仅当
config.action_controller.include_all_helpers = false
您的DashboardHelper
包含在DashboardController
中。你的.js.erb
似乎属于CommentsController
。
您必须将您的辅助方法移动到您的ApplictionController
,或者将使用helper DashboardHelper
的辅助方法包含在您要使用它的控制器中。
【讨论】:
什么不起作用?config.action_controller...
还是 DashboardHelper
中的代码仅包含在 DashboardController
中?我觉得你可能在这里有所收获。
根据文档,在 Rails 3.1 及更高版本中,默认情况下包含所有帮助程序。但只是出于好奇,如果您在CommentsController
中复制助手会发生什么?【参考方案5】:
你可以试试pluralize:
$('#<%= @card_id %> .card-comments-title').html('<%= pluralize(@comment_count, 'Comment') %>');
它应该在两个地方都有效。
我错过了你自己的后续行动。
我建议将您在多种情况下需要的助手移至application_helper.rb
文件。也许不是最佳实践,但它可以完成这项工作。
【讨论】:
【参考方案6】:尝试使用 j 表示 escape_javascript。
$('#<%= @card_id %> .card-comments-title').html('<%= j show_number_of_comments(@node) %>');
【讨论】:
Object.const_defined?("DashboardHelper")
返回什么?
当放入console.log("<%= Object...")
时返回true
。以上是关于如何从 JS ERB 内部执行辅助方法?的主要内容,如果未能解决你的问题,请参考以下文章
node js - 当函数依赖于内部的异步函数时,如何从函数返回值