如何在JavaScript中的Rails asset_path中使用动态值?

时间:2018-08-19 14:27:29

标签: javascript ruby-on-rails

基于Acquire Asset Path from JavaScript,我试图捕获图像的src

var icon = "1d0"
// ...
// some logic to get the right icon
// ...
var $icon = $("<img />", {
  class: "day-check-icon",
  src: "<%= asset_path('" + icon + ".png') %>"
})

很显然,它无法正常工作,但是它可以使我了解要实现的目标。


如果src指向我的app/assets/images/,并假设其(图像)名称存储在JavaScript变量中,该如何动态渲染图像?

1 个答案:

答案 0 :(得分:0)

就像您自己说的那样,您的榜样显然行不通。让我给您一个简短的清单,为什么在我们进入解决方案之前。

问题非常简单,服务器将文件 .erb 的所有ERB代码解析为文件,然后再将其发送给客户端。这意味着客户端将永远不会看到ERB代码,也无法与其进行交互。您可以使用ERB代码对 .js .coffee 文件进行补充,但无法采用其他方法。您遇到的另一个问题与资产摘要(默认情况下返回)有关。服务器知道这些摘要的文件路径,但是客户端不知道,除非信息由服务器提供。

外部资源(openweatherapi)也是如此,他们也不知道资产的摘要。因此,当通过客户端的JavaScript与外部资源进行交互时,您将需要某种方式将外部资源返回的资产路径转换为摘要资产路径。

最简单的解决方案是turning digestions off,但是您可以阅读here为什么通常应将其打开。

#1首先提供资产路径

假设您知道外部API始终会请求某些资产。也许您将API的映像托管在您自己的Rails服务器上,所以您不必依赖其他服务器(用于资产)。假设您将图像存储在vendor/assets/images/openweatherapi目录中,因为它们是第三方。使用以下JavaScript,您将为客户提供字典,将普通资产名称转换为摘要资产名称。

<% # lib/assets/javascripts/openweatherapi_assets.js.erb %>

<% # create a global variable assets if it doesn't exist already %>
var assets = assets || {};
assets.openweatherapi = assets.openweatherapi || {};

<% # go to path vendor/assets/images/openweather/* select all children that %>
<% # are a file and loop through each of them %>
<% Dir['vendor/assets/images/openweatherapi/*'].select(&File.method(:file?)).each do |path| %>
  <% # the asset path doesn't include the (app|lib|vendor)/assets/images/ part %>
  <% asset_path = path.sub('vendor/assets/images/', '') %>
  <% file_name = File.basename(path) %>

<% # create the dictionary %>
assets.openweatherapi['<%= file_name %>'] = '<%= asset_path(asset_path) %>';

<% end %>

别忘了将JavaScript文件包含在 application.js 中,最好在包含 app JavaScript文件之前,这样您就可以使用get变量了。现在,要从JavaScript中提取摘要的资产路径,只需在字典中搜索路径即可。

var icon = "1d0.png";
var $icon = $("<img />", {
  class: "day-check-icon",
  src: assets.openweatherapi[icon],
});

#2进行AJAX调用以获取资产路径

其他选项是通过AJAX调用将资产名称发送到服务器,并让服务器为您提供正确的摘要资产路径。通过执行以下操作可以非常简单地完成此操作:

# config/routes.rb
Rails.application.routes.draw do
  resources :assets, only: :index
end

# app/controllers/assets_controller.rb
class AssetsController < ApplicationController
  def index
    @name = params.require(:name)
  end
end

# app/views/assets/index.json.jbuilder
json.name @name
json.path asset_path(@name)

<% # app/assets/javascripts/assets.js.erb %>
<% routes = Rails.application.routes.url_helpers %>
function getAsset(name) {
  return Promise.resolve($.getJSON('<%= routes.assets_path %>', {name: name}));
}

同样,请确保该文件最好包含在 application.js 中,然后放在依赖于getAsset函数的所有文件之前。然后,您可以执行以下操作:

var icon = "1d0.png";
getAsset(icon).then(icon => {
  var $icon = $("<img />", {
    class: "day-check-icon",
    src: icon.path,
  });
});

请记住,您可以进一步优化AJAX方法,使您可以通过单个请求获取多个图标路径。但这应该给您大致的想法。还请记住,使用第一种方法可以避免AJAX调用增加了额外的嵌套和延迟。