Можно ли использовать шаблон ERB/slim вместо EJS (JST) после обновления Ajax?

Я видел много вопросов по этой теме, но нет окончательных решений. У меня есть приложение Rails 3.2, использующее ERB/slim и Coffeescript/EJS/Backbone. Я унаследовал эту кодовую базу, поэтому некоторые из этих периферийных устройств немного выше моего понимания.

Проблема

В моем представлении venue есть раздел, в котором отображаются tips, отправленные в venue. Список tips имеет функцию «сортировки», поддерживаемую JavaScript. Связанный файл CoffeeScript имеет прослушиватели событий для кликов по ссылкам для «последних» и «популярных». При щелчке JS выполняет некоторую работу и использует области Rails для пересортировки списка. Я создаю этот список tips, чтобы включить немного больше данных, в частности, включая вспомогательную функцию Rails time_ago_in_words. Исходный код обновил div, содержащий подсказки, с помощью шаблона JST/EJS в каталоге ресурсов Javascripts/templates.

Вот конкретные проблемы, с которыми я сталкиваюсь:

  1. Если я добавлю .erb в цепочку файлов (после обновления интерпретатора EJS для поиска другого шаблона оценки и интерполяции, чтобы не конфликтовать с ERB), я могу оценить основные выражения Ruby. Однако партиал не имеет доступа к той же переменной tip, на которую ссылается JavaScript. Я знаю, это потому, что Rails — это серверная часть, а JS — клиентская. Консенсуса нет, но есть ли способ передать эти данные в Rails?
  2. В то время как основные выражения Ruby могут быть вычислены (например, Time.now), помощники Rails, такие как time_ago_in_words, терпят неудачу, жалуясь, что метод не определен для класса, хотя я абсолютно передаю правильный объект даты. Можно ли не оценивать Rails/помощники в этой цепочке .EJS.ERB?
  3. Я могу обойти все эти проблемы, если есть способ сослаться на исходный частичный ERB/slim, используемый при загрузке после выполнения сортировки. Это возможно? Прямо сейчас вызываемый файл Coffeescript использует render и JST для вызова шаблона EJS. Можно ли как-то сослаться на исходный частичный, но с обновленной сортировкой?

Вот соответствующий код.

  ##show.html.erb (venue)##
  #tips
    p.sort.span4
      | Sort by: 
      = link_to 'Recent', '#', class: 'selected', id: 'sort-tips-recent'
      |  | 
      = link_to 'Popularity', '#', id: 'sort-tips-popularity'
    #tip-list
      = render resource.tips.by_recent


##tip_list_view.js.coffee##
class CS.TipListView extends Backbone.View
  el: "#tip_module"

  events:
    "click #sort-tips-recent": "sortByRecent"
    "click #sort-tips-popularity": "sortByPopularity"

  initialize: ->
    console.log("ERROR: View must be initialized with a model") unless @model
    @model.bind('reset', @render)

  render: =>
    tips = @model.map (tip) -> JST['templates/tip'](tip: tip)
    @$('#tip-list').html(tips.join("\n"))

  sortByRecent: (e) ->
    e.preventDefault()
    @model.enableSortRecent()
    @updateSelectedFilter('recent')

  sortByPopularity: (e) ->
    e.preventDefault()
    @model.enableSortPopularity()
    @updateSelectedFilter('popularity')

  updateSelectedFilter: (sort) ->
    @$('p.sort a').removeClass('selected')
   @$("p.sort a#sort-tips-#{sort}").addClass('selected')


##tip.jst.ejs.erb (called from tip_list_view.js.coffee after sort change##
<div class="tip">
  <p class="tip-author">
    <$= tip.get('user').username $>
  </p>
  <p class="tip-timestamp">
    Eventually, time goes here
  </p>
  <p class="tip-likes pull-right">
    <$= tip.upvoteCountText() $>
  </p>
  <p id="<$= tip.domId() $>">
    <$= tip.get('text') $>
    <$ if(tip.get('can_upvote')) { $>
      <a href="<$= tip.upvoteUrl() $>">upvote</a>
    <$ } $>
  </p>
<div>

Определенно в недоумении здесь - любая помощь очень ценится. Дайте мне знать, если есть какие-либо другие детали или код, которые я могу предоставить для фона. Заранее спасибо!


person justinraczak    schedule 27.11.2012    source источник
comment
Решение кажется немного хакерским, особенно с методом обновления. И с этим я все еще не понимаю, как получить данные, к которым может получить доступ JS, например, created_at, и передать их в оценку для time_ago_in_words.   -  person justinraczak    schedule 28.11.2012


Ответы (1)


С вашим ejs.erb Rails генерирует шаблон, но понятия не имеет, для чего вы будете его использовать. Затем ваше приложение Backbone получает подсказку от Rails через ajax и соответствующим образом заполняет модель. Затем ваше основное приложение заполняет и отображает шаблон. Rails не может здесь вмешиваться, по крайней мере, не в этой конфигурации, где магистраль ожидает json, а затем отображает шаблон. Все происходит на фронтенде.

Единственное, что вы можете сделать, это попросить Rails выдать вам результат ваших хелперов внутри json. Я предполагаю, что у вас есть модель Tip.rb, и она должна реализовать:

include ActionView::Helpers::DateHelper
...
def as_json(options = {})
  {
    :name => self.name,
    ... (all the model attributes that you want to expose)
    :date_age => time_ago_in_words self.created_at
  }
end

При этом я бы определенно использовал решение на стороне клиента, в том числе потому, что: http://rails-bestpractices.com/posts/105-not-use-time_ago_in_words

person standup75    schedule 27.11.2012
comment
Это работает блестяще, спасибо! Я также очень ценю указатель на идею лучших практик. Учитывая, насколько я новичок (особенно в JS), я пока буду придерживаться этого обходного пути, поскольку производительность меня пока не беспокоит, но позже я проведу рефакторинг в соответствии с лучшими практиками, используя решение на стороне клиента. Еще раз спасибо за помощь, действительно очень ценю! - person justinraczak; 28.11.2012