在资源编译中特别包含SVG文件类型
production.rb
config.assets.precompile += %w( '.svg' )
# Must include to get inline SVGs to work in deploy
config.assets.css_compressor = :sass
创建一个助手来显示 SVG
myhelper.rb
def show_svg(path)
File.open("app/assets/images/#{path}", "rb") do |file|
raw file.read
end
end
在您的视图中调用 SVG 处理助手
<%= show_svg('symbols.svg') %>
从你的问题来看,我并不是 100% 清楚你的实现,但这些步骤应该能让你看到你的 SVG 图像。一旦 SVG 可见,您就可以应用 CSS。
您可以在 Rails 中插入 svg 内联,无需任何额外的 gem,使用如下所示:
<%= render inline: Rails.root.join('public/icon.svg').read %>
如果您需要单击 svg 来执行某些操作,例如发出 POST 请求,请将整个内容包装在带有
link_to
的 do
中,如下所示:
<%= link_to some_path(@something), method: :post do %>
<%= render inline: Rails.root.join('public/icon.svg').read %>
<% end %>
您可以像显示图像一样显示 SVG。
例如在haml中:
%img{:src => "/images/image1.svg"}
希望有帮助!
我一直在尝试不同的解决方案,最终决定将 svg 文档放入
html.erb
部分。由于 svg 是有效的 html,因此将其从资产移动到视图就可以正常工作。
<%# app/views/home/index.html.erb %>
<%= render partial: "svgs/some_svg.html.erb"
给定
app
| views
| | home
| | | index.html.erb
| | svgs
| | | some_svg.html.erb
与nvm的方法类似,我有一个助手来帮助构建
use
标签的资源路径,并确保父svg
标签具有适当的属性
def external_svg(identifier, attributes = {})
# identifier: <file name without extension>#<fragment id>
file_name, fragment = identifier.split('#')
file_name += '.svg'
attributes.merge!(xmlns: 'http://www.w3.org/2000/svg')
content_tag :svg, attributes do
tag.use href: "#{image_path(file_name)}##{fragment}"
end
end
在视图中,您的 SVG 资源将被称为:
external_svg 'symbols#icon-search', class: 'icon'
,生成的 html:
<svg xmlns="http://www.w3.org/2000/svg" class="icon">
<use href="<asset pipeline path>/symbols.svg#icon-search" />
</svg>
由于外部引用的 SVG 现在得到了良好的支持,因此您不需要任何 SVG 特定的 gem 即可实现此功能。
使用这种方法时值得注意的优点(缓存)和缺点(CSS 样式限制)。请参阅此 Twitter 帖子
对于
ActiveStorage
,根据Elvn的回复,我发现有更好的方法
如果您有一个带有
item
的 has_one_attached :logo
物体:
<%= show_svg(item.logo_blob) %>
那么助手就是:
def show_svg(blob)
blob.open do |file|
raw file.read
end
end
很简单:
首先将svg添加到assets.rb中的资源预编译列表中
application.config.assets.precompile +=
%w(<your other files> symbol-defs.svg)
然后在 erb/haml 文件中引用它,如下所示:
<svg class="icon gr-menu">
<use xlink:href="<%= asset_path('symbol-defs') %>#gr-menu"></use>
</svg>
创建一个助手:(每种情况的内容都不同,自定义您自己的)
def icon(icon, css_class: "")
content_tag(:svg, class: "icon icon_#{icon} #{css_class}") do
content_tag(:use, nil, 'xlink:href' => "#icon_#{icon}")
end
end
像这样使用它:
<%= icon 'arrow-menu' , css_class: 'arrow-breadcrumb' %>
如果你可以使用 inline_svg gem。它很旧但仍然有效的解决方案维护得很好
如果您不能(例如公司政策),简而言之,这就是 gem 的作用:
# app/helpers/svg_helper.rb
module SvgHelper
SVGFileNotFoundError = Class.new(StandardError)
def inline_svg_tag(path, options = {})
path = Rails.root.join("app/assets/images/#{path}.svg")
File.exist?(path) || raise(SVGFileNotFoundError, "SVG icon file does not exist: #{path}")
svg_file_content = File.binread(path)
if options.any?
doc = Nokogiri::XML::Document.parse(svg_file_content)
svg = doc.at_css("svg")
svg["height"] = options[:height] if options[:height]
svg["width"] = options[:width] if options[:width]
svg["class"] = options[:class] if options[:class]
svg_file_content = doc.to_html.strip
end
raw svg_file_content
end
end
测试:
# spec/helpers/svg_helpers_spec.rb
require "rails_helper"
RSpec.describe SvgHelper do
describe "#inline_svg_tag" do
it "raises an error when the file does not exist" do
expect { helper.inline_svg_tag("does-not-exist") }.to raise_error(SvgHelper::SVGFileNotFoundError)
end
it "when no options passed returns the SVG file contents with original HTML attribute values" do
result = helper.inline_svg_tag("icons/profile")
expect(result).to include("<svg")
expect(result).to include('height="20"')
expect(result).to include('width="20"')
expect(result).not_to include("class")
end
it "when class option passed returns the SVG file contents with class HTML attribute" do
result = helper.inline_svg_tag("icons/profile", class: "whatever")
expect(result).to include("<svg")
expect(result).to include('class="whatever"')
end
it "when height passed returns the SVG file contents with new height" do
result = helper.inline_svg_tag("icons/profile", height: "12345")
expect(result).to include("<svg")
expect(result).not_to include('height="20"')
expect(result).to include('height="12345"')
end
it "when width passed returns the SVG file contents with new width" do
result = helper.inline_svg_tag("icons/profile", width: "54321")
expect(result).to include("<svg")
expect(result).not_to include('width="20"')
expect(result).to include('width="54321"')
end
end
end
我真的不知道如何解析SVG文件;但同样的事情也可以用于 SVG 文件。然后,您可以在 SVG 文件中使用 asset_path 助手;但问题是 Rails 默认解析 CSS、JS 和 ERB。这样,SVG 内部的链接就可以与资源管道配合使用。也许如果您尝试将名称从“symbols.svg”更改为“symbols.svg.erb”,它会解析文件以获取正确的网址。
你的问题是资产管道没有按照rails使用。
这就是解析(预处理)svg 文件的方法:
编译文件的默认匹配器包括application.js, application.css 和所有非 JS/CSS 文件(这将包括所有图像 自动资产)从应用程序/资产文件夹,包括你的宝石:[ Proc.new { |文件名,路径|路径 =~ /app/assets/ && !%w(.js .css).include?(File.extname(文件名)) }, /application.(css|js)$/ ]
有关助手方法的更多信息
2.3.2 CSS 和 Sass
使用资产管道时,必须重写资产路径并 sass-rails 提供 -url 和 -path 帮助器(在 Sass 中连字符, 在 Ruby 中下划线)用于以下资产类别:图像、字体、 视频、音频、JavaScript 和样式表。
image-url("rails.png") becomes url(/assets/rails.png) image-path("rails.png") becomes "/assets/rails.png".
也可以使用更通用的形式:
asset-url("rails.png") becomes url(/assets/rails.png) asset-path("rails.png") becomes "/assets/rails.png"
2.3.3 JavaScript/CoffeeScript 和 ERB
如果您向 JavaScript 资产添加 erb 扩展,使其成为某种东西 例如 application.js.erb,然后您可以在中使用 asset_path 帮助器 你的 JavaScript 代码: $('#logo').attr({ src: "<%= asset_path('logo.png') %>" });
这将写入所引用的特定资产的路径。
同样,您可以在 CoffeeScript 文件中使用 asset_path 帮助器 带有 erb 扩展名(例如 application.js.coffee.erb):$('#logo').attr 来源:“<%= asset_path('logo.png') %>”
您可以检查: http://guides.rubyonrails.org/asset_pipeline.html#coding-links-to-assets