Генерация JavaScript в Sinatra helpers

#javascript #ruby #sinatra #haml

#javascript #ruby #sinatra #haml

Вопрос:

Я использую Haml в качестве языка шаблонов в веб-приложении на базе Sinatra, и у меня возникли проблемы с генерацией массива JavaScript на основе информации из модели базы данных. По сути, я пытаюсь сгенерировать массив JavaScript, состоящий из имен пользователей, для использования в виджете автозаполнения jQuery-UI.

Я попробовал следующий код, но он не сработал.

 :javascript
  var names = new Array;
  - User.all.each do |u|
    names.push(#{u})
  

После прочтения большинство людей предлагают делать все, что связано с вычислением Ruby (т. Е. Чего-либо с префиксом ‘-‘ в Haml) в помощнике вместо этого. Итак, учитывая это, кто-нибудь может объяснить мне, как сгенерировать JavaScript в вспомогательном методе?

Ответ №1:

Проблема здесь в том, что вы не можете использовать обычные функции haml в фильтре (например, :javascript ). Однако текст в фильтре подвергается обычной интерполяции строк ruby, т. Е. все, что находится внутри #{} , выполняется как код Ruby.

Итак, одним из способов заставить ваш пример работать было бы что-то вроде:

 :javascript
  var names = new Array;
  #{js = ""
  User.all.each {|u| js << "names.push(#{u})n" }
  js}
  

Однако это довольно запутанный процесс, и способ привести его в порядок — переместить в помощник. Помощник — это просто метод, который находится в области видимости во время рендеринга (поэтому его можно вызвать в файле haml) и генерирует некоторый текст для включения в сгенерированную страницу.

В этом случае вы генерируете javascript, но javascript — это просто текст, поэтому здесь нет проблем. Вспомогательный метод мог бы выглядеть примерно так:

 def js_array(name, array)
  js = "var #{name} = new Array();n"
  array.each do |i|
    js << "#{name}.push(#{i})n"
  end
  js
end
  

(Или вы могли бы создать литеральный массив javascript:

 def js_array(name, array)
  js = "var #{name} = ["
  js << array.collect{|i| ""#{i}""}.join(",")
  js << "]"
  js
end
  

если вы предпочитаете.)

Далее, куда направляется этот метод? В Sinatra вы определяете вспомогательные методы, используя метод ‘helpers`. Любые методы, определенные в этом блоке, будут доступны в ваших представлениях:

 helpers do
  def js_array(name, array)
    js = "var #{name} = new Array();n"
    array.each do |i|
      js << "#{name}.push(#{i})n"
    end
    js
  end
end
  

После этого вы можете выполнить

 :javascript
  #{js_array("names", User.all)}
  

в вашем haml для генерации вашего массива javascript. Обратите внимание, что вам все еще нужен #{} , чтобы код ruby был выполнен, только теперь у вас есть только один вызов метода между фигурными скобками. :javascript Фильтр заключит блок в теги <script> и <![CDATA[ , а помощник создаст фактический javascript, который вы хотите.

Еще одна вещь: в вашем примере массив является User.all , который выглядит как вызов activerecord или что-то подобное, и в этом случае у вас может быть массив не строк, а какого-то другого объекта, который может не дать желаемого результата. Возможно, вам потребуется сделать что-то вроде:

 :javascript
  #{js_array("names", User.all.collect(amp;:pretty_name)}
  

(где pretty_name — это метод для User объекта, который возвращает имя для печати), или, возможно, измените вспомогательный метод, чтобы извлечь строку, которую вы хотите использовать.

Комментарии:

1. Потрясающе, спасибо, Мэтт! Я отмечаю это как ответ, потому что в нем показано, как использовать помощник для генерации javascript для использования с haml.

Ответ №2:

Вместо того, чтобы вспомогательный метод генерировал JavaScript, вы, вероятно, хотите, чтобы он возвращал массив имен, которые затем можно использовать в качестве источника для виджета автозаполнения пользовательского интерфейса jQuery в представлении.

Итак, ваш вспомогательный метод будет выглядеть примерно так:

 helpers do
  # Return an array of users' names
  def get_all_names
    return User.all.map {|u| u.name}
  end
end
  

И в вашем Haml:

 :javascript
  $(function() {
    var names = #{get_all_names.to_json};
    $("#widget").autocomplete({ source: names });
  }); 
  

Комментарии:

1. Спасибо, Кунал! Это тоже было полезно, потому что это говорит мне, как использовать результаты из помощника в существующей функции javascript.