How to add markdown as a preprocessor to the asset pipeline? - ruby-on-rails

I have markdown files in app/assets/md/*.html.md which I would like to precompile with rake assets:precompile.
How can I set the asset pipeline up so that it will use a markdown parser to produce the expected HTML files?
Also, how can I include these precompiled assets directly within my views, such as:
<div>
<%= yield asset("my_markdown_fragment.html") %>
</div>

I have since found the solution. Here is what I did:
Add rdiscount to the Gemfile (rdiscount is a Markdown processor for Ruby):
gem 'rdiscount'
Create the file lib/markdown_preprocessor.rb with these contents:
require 'rdiscount'
class MarkdownPreprocessor < Sprockets::Processor
def evaluate(context, locals)
RDiscount.new(begin;data;end).to_html
end
end
Add the MarkdownPreprocessor to the asset pipeline in the config/initializers/sprockets.rb file (create this file if it does not exist) like this:
require 'markdown_preprocessor'
Rails.application.assets.register_engine('.md', MarkdownPreprocessor)
Add the following line to the config/initializers/assets.rb file:
Rails.application.config.assets.paths << Rails.root.join('app', 'assets', 'md')
Configuration is done now. Here are some other guides and tips:
Place your Markdown files into the app/assets/md/ folder.
The extension of your files end with .md, but I suggest .html.md (since the result is an HTML file).
You can insert <%= ruby %> into your Markdown files when you add the .erb extension. For example, try creating this file app/assets/md/hello.html.md.erb with the following contents:
# Hello <%= "_World_ " * 42 %>
You can access the resulting HTML content in your views and controllers with:
Rails.application.assets[asset_path].to_s.html_safe

Related

unable to determine if controller based asset exists without .js extension rails

I have added assets for a controller and wants to include them per request.
The problem is that it does not include that assets without writing .js in controller path
The code on layout page is:
<%= controller_specific_js = "#{params[:controller]}.js" %>
<%= javascript_include_tag controller_specific_js if asset_exist?
(controller_specific_js) %>
Helper method:
def asset_exist?(path)
if Rails.configuration.assets.compile
Rails.application.precompiled_assets.include? path
else
Rails.application.assets_manifest.assets[path].present?
end
end
The assets are in admin/popular_schools that are admin/popular_schools.js.coffee
<%= controller_specific_js = "#{params[:controller]}.js" %>
The above line outputs: admin/popular_schools.js and adds it.
URL is: http://localhost:3000/admin/popular_schools
assets.rb:
Rails.application.config.assets.precompile += %w( admin/popular_schools.js.coffee )
production.rb
config.assets.compile = true
How exactly I can run it without specifying .js in "#{params[:controller]}.js" as conventially its is not good.
If I remove .js it does not insert it in assets but if I include it it starts to appear.
Also if I use below code:
<%= controller_specific_js = "#{params[:controller]}" %>
<%= javascript_include_tag controller_specific_js if asset_exist?(controller_specific_js) %>
It does work without specifying .js but if I do not want to include any controllers in assets.rb file they start to output exception that file is not included in the assets.erb but it does included in assets folder and for some reasons I do not want to include them in assets.rb
Any workaround or conventions?

How to copy over /public folder of Rails Engine to a Rails application in production?

I know a simple solution would be just to manually copy over all the files in the Rails Engine's /public folder to the Rails application's /public folder. However, this means that each installation would require manually copying.
Furthermore because the Javascript files that my engine uses have hard-coded image paths, I cannot simply throw all my static files under app/assets or vendor/assets, as then Rails would copy them over to public/assets. I can't change the path where Sprockets outputs the files as I have other gems that expect their assets to be in the default public/assets folder.
I tried doing something like
class Engine < ::Rails::Engine
if Rails.application.config.serve_static_assets
initializer "static assets" do |app|
app.middleware.insert_before(::ActionDispatch::Static, ::ActionDispatch::Static, "#{root}/public")
end
end
end
but this only works for development.
Personally, I believe that the best solution would be to update your javascript files to follow Rails' conventions by replacing the hard-coded images in the javascript with the asset path helper - http://guides.rubyonrails.org/asset_pipeline.html#coding-links-to-assets and then throwing everything into app/assets.
With that said, I can think of situations where you may not want to do that, and that may be the case here.
From your post, I'm guessing that you're precompiling assets for production (i.e. - running rake assets:precompile). In that case, you can just hook into the assets:precompile rake task and copy the files over. It would look something like this in your engine's lib/tasks/my_engine_tasks.rake:
Rake::Task["assets:precompile"].enhance do
Rake::Task["my_engine:copy_assets"].invoke
end
namespace :my_engine do
task :copy_assets => :"assets:environment" do
assets = ["file1", "file2"]
assets.each do |asset|
source_file = File.join(MyEngine::Engine.root, 'public', asset)
dest_file = File.join(Rails.root, 'public', asset)
FileUtils.copy_file source_file, dest_file, true
end
end
end
The above is a simple copy operation but you can also manually run sprockets over those files as well. Take a look at the code for the assets:precompile task (lib/sprockets/rails/task.rb in the sprockets-rails gem) and the Sprockets Manifest class (lib/sprockets/manifest.rb in the sprockets gem).
Seems Rails doesnt provide an obvious way to serve static assets from an engine. So heres my dynamic solution for this problem.
module MyApp
class Engine < ::Rails::Engine
isolate_namespace MyApp
initializer "my_app.assets.precompile" do |app|
app.config.assets.precompile << "my_app_manifest.js" ### manifest file required
### Precompile all static assets
### Note in this example use a non-standard folder (app/assets/public/)
["app/assets/images/", "app/assets/public/"].each do |folder|
dir = app.root.join(folder)
if Dir.exist?(dir)
Dir.glob(File.join(dir, "**/*")).each do |f|
asset_name = f.to_s
.split(folder).last # Remove fullpath
.sub(/^\/*/, '') ### Remove leading '/'
app.config.assets.precompile << asset_name
end
end
end
end
end
end

Rails - How to set 1 scss file for 1 view

I can't figure out how make certain .scss files work with certain views. I removed the *= require_tree . from the application.css.scss but I'm not sure where to go from there. The stylesheet_link_tag doesn't seem to recognize .scss files. What tag can I use to import .scss files to views?
I also tried creating a different controller for the different view but after I removed the require_tree the controller doesn't use the .scss file that was automatically generated with it.
In application.css remove *= require_tree.
In application.html add:
<head>
<%= yield :stylesheets %>
</head>
And on every page render:
<% content_for :stylesheets do %>
<%= stylesheet_link_tag "your file" %>
<% end %>
The most important piece you are probably missing is that Sprockets won't serve any asset, mainly the css and js need to be declared in your asset manifest. Quoting the docs:
If you have other manifests or individual stylesheets and JavaScript files to include, you can add them to the precompile array in config/initializers/assets.rb:
Rails.application.config.assets.precompile += ['admin.js', 'admin.css', 'swfObject.js']
Use the expected resulting name (with .css extension) and not the source file (with the .scss extension).
There is a way to organize your assets based on controller.
Rails guide has a section about it.
According to it you can create app/assets/stylesheets/projects.css.scss file for your ProjectsController and include it like this:
<%= stylesheet_link_tag params[:controller] %>
When doing this, ensure you are not using the require_tree directive, as that will result in your assets being included more than once.
Action based stylesheets can be created similarly:
<%= stylesheet_link_tag "#{params[:controller]}/#{params[:action]}" %>
if the scss file is in the root of the asset folder then
add line to your view file
=stylesheet_link_tag 'your_scss_file_name'
in \config\initializers\assets.rb
add this line
Rails.application.config.assets.precompile + =% w (your_scss_file_name.css)

Sprockets not adding fingerprint to files added in scss file

I'm having an issue with Rails, Sprockets, SCSS and them not adding a fingerprint to the generated image files.
When I try to precompile my assets in an environment other than development, I get the following error:
rake aborted!
Custom asset_path helper is not implemented
Extend your environment context with a custom method.
environment.context_class.class_eval do
def asset_path(path, options = {})
end
end
So I add the following to an initializer:
Rails.application.assets.context_class.class_eval do
def asset_path(path, options = {})
end
end
Which causes the error to go away, although I don't know if this is the right way about fixing the issue. It then produces a new error:
undefined method `include?' for nil:NilClass
However, if I add the following code:
Rails.application.assets.context_class.class_eval do
def asset_path(path, options = {})
"/assets/#{path}"
end
end
It precompiles fine, but then the generated css does not have the fingerprint generated at the end of the url and therefore doesn't load when viewing the page.
The weird thing is that images that aren't added in a scss file, like in an img tag in the html, has the fingerprint appended fine and shows up when viewing the page.
Here is an example of some scss that doesn't load the fingerprint:
background: $blue url( asset-path('hero/hero-bg.jpg') ) repeat-x;
I'm running Rails 4.0.2. Here is my gemfile: https://gist.github.com/anthonycollini/8025540
Any help would be greatly appreciated. Thank you.
You shouldn't have to define asset_path since that is a helper that is already provided by Rails. It looks like you may have missed <%= %> when using asset_path in your scss file.
background: $blue url(<%= asset-path('hero/hero-bg.jpg') %>) repeat-x;
Also, don't forget to add the .erb file extension on your scss file like example.css.scss.erb.
Hope that helps!

Use assets in folder only when on page X

I've got a folder of js files that I want to include only when I'm on my dashboard page(or controller).
Can I exclude that folder from my application.js's //= require_tree . file and only include it in my dashboard?
You can have application.js require only some files, rather than the everything-and-the-kitchen-sink approach of require_tree .
For instance, make a directory structure like this:
javascripts/
application.js
special.js
common/
foo.js
bar.js
special/
other.js
Then have application.js only include files in the "common" directory by using
= require_tree ./common
Meanwhile, "special.js" (find a better name, obviously), require everything in "special"
= require_tree ./special
Then you'll have to tell Rails that "special.js" should be pre-compiled by the asset pipeline (if you do use asset precompilation). This is done in config/production.rb, and there's already a commented line there showing to to do it. So just uncomment and edit that line, and you should get:
config.assets.precompile += %w( special.js )
If you don't do this, the precompilation will only look at application.js (the default)
Finally, in the relevant views, you can include the special JS by saying
<%= javascript_include_tag "special" %>
You can just place that at the bottom of the file
You can create another js file - dashboard.js, and include it only for dashboard controller
<% if current_page?(:controller => 'dashboard') %>
<%= javascript_include_tag 'dashboard' %>
<% else %>
<%= javascript_include_tag 'application' %>
<% end %>
In your environments/production.rb just add
config.assets.precompile += %w(dashboard.js)

Resources