3

I develop a rails app with exercises (for kids with learning difficulties in math). The interactive part of the exercises is written in javascript. I store each exercise in a database. The javascript contains

<%= asset_path('to_images') %>

I can read the scripts into the controller and write the content to a partial, but I think it would be better to capture the scripts in a variable, like:

@animation = exercise.animation

where any code containing <%= asset_path(...) %> would be replaced with the correct fingerprinted route to the asset.

Here is an example of a code snippet in exercise.animation:

$("#hundred_square td").css({
    backgroundImage: 'url(<%= asset_path("exercises/shapes/circles/circle_open_black_48.png") %>)',
    backgroundSize: "2vw",
    backgroundRepeat: "no-repeat",
    backgroundPosition: "center"
});

I have already tried to

class Exercise < ActiveRecord::Base
include ActionView::Helpers::AssetUrlHelper

and

self.animation.gsub(/\<\%\=\s*asset_path\((.+)\)\s*\%\>/) do |match|
  address = $1
  puts "#{address}"
       =>  "exercises/shapes/circles/circle_open_black_48.png"
  puts "#{asset_path(address)}"
       =>  /"exercises/shapes/circles/circle_open_black_48.png"
  puts "#{ActionController::Base.helpers.asset_path(address)}"
       =>  /"exercises/shapes/circles/circle_open_black_48.png"
end

do not produce the result I need. Thanks for your suggestions!

Daniela
  • 234
  • 2
  • 13
  • Are you are trying to execute Ruby ERB within Javascript? – Kelsey Hannan Oct 25 '16 at 21:23
  • Why trying? In .erb files the ruby code is handled first. If I read the javascript code (including ruby code) into the controller and then write it into a partial, all works beautifully. – Daniela Oct 25 '16 at 21:35
  • I see, so you're using a `js.erb` file. Is your problem that this ERB is not correctly being parsed into an asset path within the view, or is it that you can't access the helper method within your Model? – Kelsey Hannan Oct 25 '16 at 21:37
  • Thanks Kelseydh. I am not using a js.erb file in this case. I am storing the javascript code in the database (with its exercise). When I read that code, I would like to have a way to have the controller (or even better the model) deal with the code as if it was a template, to replace the <%= ... %> code (which I can do) and then make it into a route including the fingerprint. (See the last 2 paragraphs, from "I have already tried to") - I need a result like: 'url(/assets/exercises/shapes/circles/circle_open_black_48-d6e60117aaf82eb468c535ce7705abced4008ddda9010adf30b0c030ad568632.png)' – Daniela Oct 25 '16 at 21:41
  • Just as an aside, if any of the javascript you are storing in the database contains the results of user input I would advise against storing JS in your database as it will make your app susceptible to XSS attacks. (e.g. If someone publicly can execute `alert("pwned")` from the JS you may have an issue ) – Kelsey Hannan Oct 25 '16 at 21:56
  • I know - do you have any ideas how to solve my problem? – Daniela Oct 25 '16 at 22:40
  • Just to be clear, can you confirm you can successfully get the fingerprint for these assets when you call `asset_path` from within the view? If not, get fingerprint working there first. – Kelsey Hannan Oct 25 '16 at 23:28

1 Answers1

3

One way to fetch the MD5 fingerprint value is to use Sprockets' find_asset method, passing in a logical path to your asset to get a Sprockets::BundledAsset instance. For example

[1] pry(main)> Rails.application.assets.find_asset('application.js')
=> #<Sprockets::BundledAsset:0x3fe368ab8070 pathname="/Users/deefour/Sites/MyApp/app/assets/javascripts/application.js", mtime=2013-02-03 15:33:57 -0500, digest="ab07585c8c7b5329878b1c51ed68831e">

You can call digest_path on this object to get it's MD5 sum appended to the asset.

[1] pry(main)> Rails.application.assets.find_asset('application.js').digest_path
=> "application-ab07585c8c7b5329878b1c51ed68831e.js"

With this knowledge you can create a helper to return the digest_path for any asset in your application, call this helper from within your .js.erb files or from within your model.

See this answer for more details on this approach.

Community
  • 1
  • 1
Kelsey Hannan
  • 2,857
  • 2
  • 30
  • 46