Как выполнить вспомогательный метод из JS ERB?

У меня есть вспомогательный метод в моем 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 пустым значением.

Ответ 1

Итак, я понял, что я хотел бы сделать в своем конкретном случае, то есть плюрализировать количество комментариев в моей JS ERB, но я не понял, как использовать helper_method из моей JS ERB - так что этот ответ doesn На этот вопрос я действительно отвечаю.

Однако я документирую это здесь, если у кого-то есть аналогичная проблема, и мое решение помогает им.

В моем JS ERB все, что я сделал, было использовано методом Rails pluralize. Я полностью забыл об этом, пока не набрал этот вопрос, и он работает как шарм.

Вот фрагмент кода для моего create.js.erb:

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

Работает как шарм, но это все еще не отвечает на мой вопрос о ссылках/использовании вспомогательных методов здесь.

Ответ 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) %>");

По проблеме с неработающими помощниками: учитывая, что у вас есть dashboard_helper.rb в каталоге app/helpers/, ваш помощник должен работать. С проблемой, которую вы описали, где работает следующая строка:

$('#<%= @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) %>');

Ответ 4

Изменить. Для Rails 3.1+ следующее верно только в том случае, если

config.action_controller.include_all_helpers = false

Ваш DashboardHelper включен в DashboardController. Ваш .js.erb, кажется, принадлежит чем-то вроде CommentsController.

Вам придется либо переместить ваш вспомогательный метод в ваш ApplictionController, либо включить помощника, используя helper DashboardHelper в контроллере, в котором вы хотите его использовать.

Ответ 5

Вы можете попробовать pluralize:

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

Он должен работать в обоих местах.

Я пропустил ваше собственное наблюдение.

Я бы предложил переместить помощников, которые вам нужны в нескольких контекстах, в файл application_helper.rb. Возможно, это не самая лучшая практика, но она будет выполнять эту работу.

Ответ 6

Попробуйте использовать j short для escape_javascript.

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