如何从 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_helperapplication_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: &lt;%= j show_number_of_comments(@node) %&gt;"); 时会打印出:@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_countcounter_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("&lt;%= Object...")时返回true

以上是关于如何从 JS ERB 内部执行辅助方法?的主要内容,如果未能解决你的问题,请参考以下文章

如何从Meteor.js中的方法内部的方法返回错误

node js - 当函数依赖于内部的异步函数时,如何从函数返回值

Nuxt.js:如何重定向内部方法

js 如何循环执行同一方法

Rails update.js.erb 不执行 javascript

Rails js.erb 文件未执行