如何在JS ERB中调用一个辅助方法?

14

我在我的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
----------------------------------------

此外,在我的Comments#Create中声明了@node对象,如下所示:

  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方法可以将逻辑与表示解耦,您尝试过吗? - Anatoly
“它不起作用”确切意思是什么?您是否收到了未定义方法错误? - amiuhle
在你的 HTML 视图中,你使用 node 调用帮助方法,在你的 JS 中你使用 @node 调用它。 - amiuhle
6个回答

5
所以,我已经确定了我在特定情况下想要做的事情,即在我的JS ERB中复数化评论计数,但我还没有弄清楚如何在我的JS ERB中使用helper_method - 所以这个答案实际上并没有回答这个问题。
然而,如果有人有类似的问题,我的解决方案可能会对他们有所帮助,因此我在此记录一下。
在我的JS ERB中,我只是使用了Rails方法pluralize。我完全忘记它直到我打出这个问题,它像魔法一样工作。
这是我的create.js.erb的代码片段:
$('#<%= @card_id %> .card-comments-title').html('<%= pluralize(@comment_count, "Comment") %>');

功能非常好,但这仍然没有回答我的问题,关于在这里引用/使用辅助方法。


2
我不确定这个问题是否已得到解答。只是想回答一下,因为现在我很好奇我的helpers是否在js.erb中起作用。我认为你的@node在create.js.erb文件中不可用,这就是为什么它对你不起作用的原因。即使你调用了pluralize,pluralize仍然是一个被调用的帮助方法。如果你的'@node'不存在,node.comments_count必须会崩溃。 - Athar
1
是的,在erb中可以调用helpers,无论是js还是html都可以。我认为和@Athar一样:@node很可能是nil。 - nathanvda
@Athar 我相信你可能有正确的答案。写成一个答案,我会接受它。你是对的,因为 pluralize 起作用了(这是 Rails 的帮助程序)。 - marcamillion
@Athar,我测试了你的想法,结果发现@node实际上被正确设置了。我更新了问题并添加了更多的调试细节。 - marcamillion
由于问题仍然存在,我不会发布答案。我想到的第二种情况是无法从comments#create.js.erb调用dashboard_helper方法,尽管这不应该发生,但我很遗憾无法复制此操作。如果我是你,我会先将此方法移动到comments_helperapplication_helper中并调用,以确认问题是否出在方法或帮助程序文件上。如果该方法可以从那里工作,则问题可能出在dashboard helper文件中。该文件位于哪里?app/helpers/dashboard_helper - Athar

4
您可以尝试避免使用后端,如果不需要本地化:
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);

这是一个有趣的方法,但并没有完全回答我想知道的关于辅助方法的问题。 - marcamillion

3
一种更好的显示单数/复数文本的可能解决方案是通过国际化。您可以尝试以下内容:
# 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) %>');

如果您使用console.log输出show_number_of_comments(@node),可能会找到更好的答案。很可能需要使用escape_javascript来转义此输出结果。因此,虽然不是一个具体的解决方案,我建议您尝试:

$('#<%= @card_id %> .card-comments-title').html('<%= j show_number_of_comments(@node) %>');

我尝试使用escape_javascript进行转义,但是没有成功。 - marcamillion
另外,更好的方法是使用Rails助手方法pluralize来实现,我相信它使用了I18n。当我尝试执行console.log("@Node is: <%= j show_number_of_comments(@node) %>");时,它会打印出:@Node is: 8 Comments,其中8是提交此评论之前的评论数量,因此理论上应该输出...9 Comments而不是8 - marcamillion
i18n添加了pluralize,但尚未发布!它只存在于master分支,而不是4.2 stable。如果您之前已查询了@node,则不会发生您预期的下一个理论行为。如果您重新分配带有查询的@node,则将得到“9条评论”。 - vee
1
阅读您的编辑后,我建议您通过@node而不是通过current_user来构建comment。 因此,使用@node.comments.new(comment_params)并将其分配给current_user。这将允许您使用@node.comments.length而不是额外的变量@comment_count - vee
请记住,无论我如何处理它,我都必须增加评论计数,并且@node.comments_count直接来自列,而不是Ruby方法 - 因此我不确定这个建议是否更有效。也就是说,当comment_count是一个counter_cache时,@node.comments.length@node.comment_count更有效吗?我表示怀疑。 - marcamillion
啊,如果你的节点有“has_many:comments”,我认为你不需要增加评论计数。出于性能原因,您可能会有不同的实现。这可能更好地通过基准测试进行测试。我的建议是避免使用额外的方法“show_number_of_comments”,因为如果您使用“counter_cache”,AR已经提供了它! - vee

1

编辑:对于Rails 3.1+而言,以下内容仅在以下情况成立。

config.action_controller.include_all_helpers = false

你的DashboardHelper被包含在DashboardController中。你的.js.erb文件似乎属于类似CommentsController的东西。
你需要将helper方法移动到ApplicationController中,或者在想要使用它的控制器中使用helper DashboardHelper来包含helper。

什么不起作用?是config.action_controller...还是DashboardHelper中的代码只包含在DashboardController中?我觉得你可能有所发现。 - marcamillion
根据文档,在Rails 3.1及更高版本中,默认情况下所有的helpers都已经包含。但是出于好奇,如果在CommentsController中重复使用helper会发生什么? - amiuhle

0

你可以尝试复数形式

$('#<%= @card_id %> .card-comments-title').html('<%= pluralize(@comment_count, 'Comment') %>');

它应该在两个地方都能工作。

我错过了你的后续回复。

我建议将你在多个上下文中需要的帮助程序移动到application_helper.rb文件中。也许不是最好的做法,但它可以完成工作。


0

尝试使用简称为escape_javascript的j。

$('#<%= @card_id %> .card-comments-title').html('<%= j show_number_of_comments(@node) %>');

Object.const_defined?("DashboardHelper") 返回什么? - daslicious
当放置在 console.log("<%= Object...") 中时,它会返回 true - marcamillion

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接