Звездочки › Как указать привязку для оценки/рендеринга Erb?

Я провел много времени, копаясь в исходном коде sprockets и tit, пытаясь выяснить, как передать переменные/привязки в контекст оценки Erb. Вот что я пытаюсь сделать: мне нужно обслуживать файл JS, содержимое которого изменяется для каждого запроса. Части, которые изменяются, зависят от данных, хранящихся в БД, поэтому необходимо направлять запросы через приложение Rails и передавать переменные/привязки. Кроме того, файл JS использует директивы require для вставки других файлов JS, поэтому необходимо использовать звездочки.

Вот фрагмент кода, который не работает:

Файл контроллера:

def ever_changing_js
  @foobars = Foobar.all
  MyApp::Application.assets.instance_eval do
    def foobars
      @foobars
    end
  end

  render :text => MyApp::Application.assets.find_asset('ever_changing.js').to_s, :content_type => "application/javascript"
end

ever_changing.js:

//= require file1.js
//= require file2.js

// Some code that uses @foobars

Как я могу это сделать? Любая помощь будет оценена по достоинству.


person Saurabh Nanda    schedule 15.09.2012    source источник


Ответы (2)


Файлы JavaScript должны быть полностью статичными; Звездочки не предназначены для того, чтобы делать то, что вы пытаетесь сделать.

Любые данные, которые изменяются для каждого запроса, должны быть записаны в тег <script> в нижней части отображаемого шаблона.

приложение/активы/javascripts/user.js

(function(exports) {
  function User(name) {
    this.name = name;
  }

  User.prototype.speak() {
    console.log(this.name + ' says, "Hello!"');
  };

  exports.User = User;
})(this);

приложение/представления/пользователи/show.html.erb

...

  <%= javascript_include_tag('user') %>
  <script>
    (function() {
      var user = new User(<%= @user.name %>);

      $('#speak-button').click(function() {
        user.speak();
      });
    })();
  </script>
</html>

Если вы можете предоставить больше информации о вашем конкретном случае использования, я могу привести более конкретный пример.

person Ross Allen    schedule 03.11.2012
comment
Спасибо за ваш ответ ssorallen. К сожалению, в моем случае нет связанного файла шаблона. Позволь мне объяснить. Рассматриваемый JS может использоваться различными пользователями приложения для отображения виджета на их веб-сайте. (Вспомните виджет живого чата, который люди устанавливают на свои сайты). Теперь у каждого пользователя могут быть разные настройки + данные, которые необходимо указать в JS-файле. Я хочу обернуть статическую часть JS и динамическую часть JS в один файл и обслуживать его. Имеет ли это смысл? - person Saurabh Nanda; 04.11.2012
comment
API-интерфейсы JavaScript, такие как Google Maps, обслуживают один и тот же JS для каждого клиента и просят клиента создать экземпляры объектов и API, которые ему нужны. - person Ross Allen; 04.11.2012
comment
Если вам действительно нужен динамический файл JavaScript, назовите свой шаблон, например, .js.erb, и Rails вернет правильный тип MIME для JavaScript для запроса. Он должен жить в app/views вместо app/assets. - person Ross Allen; 04.11.2012
comment
Я не могу просить клиента создавать экземпляры объектов так, как ему нравится, потому что это стало бы слишком технически. В идеале клиент должен использовать веб-интерфейс для изменения настроек и включать только один JS-файл на свой веб-сайт. - person Saurabh Nanda; 04.11.2012
comment
Если я использую файл .js.erb, могу ли я использовать директивы //= require вверху? Мне нужно, чтобы окончательный файл JS был конкатенированной версией 3-4 других файлов JS + динамические биты. - person Saurabh Nanda; 04.11.2012

Я пытаюсь добиться того же, что и вы. Я вижу пару проблем с вашим фрагментом кода контроллера. Вместо того, чтобы делать instance_eval на Sprockets::Environment, вы должны class_eval на context_class, как показано в Sprockets::Context документация.

MyApp::Application.assets.context_class.class_eval do
  def foobars
    @foobars
  end
end

Тогда foobars будет доступен для вашего шаблона ERb.

В качестве примечания вы можете сделать

render js: MyApp::Application.assets.find_asset('ever_changing.js').to_s

вместо того, чтобы устанавливать тип контента самостоятельно.

person Adam Stegman    schedule 01.02.2013