Pass options to Sprocket Engines - ruby-on-rails

I need to be using double quotes on my attributes due to a Javascript framework issue I am having, and I have tried setting the Haml::Template.options hash as the documentation recommends when using Rails, however isn't taking affect for the 'assets' folder, regardless of where I am setting the option. Note, it is working on normal ActionView templates being rendered by Rails controllers, but not in templates I have under {Rails.root}/app/assets/javascripts/templates/*.html.haml
This is what I have in {Rails.root}/config/initializers/haml.rb:
Haml::Template.options[:attr_wrapper] = '"'
# Adds the ability to use HAML templates in the asset pipeline for use with
# Batman.js partials
Rails.application.assets.register_mime_type 'text/html', '.html'
Rails.application.assets.register_engine '.haml', Tilt::HamlTemplate
I've also tried changing the register_engine to use Haml::Engine and Haml::Template, which both render, but still don't take my options I set above.
How do I set the Haml options for rendering in the asset pipeline? It seems like I need to pass in options for the Sprocket engine?

I found the solution here.
It's all about monkey patching.
I prefer this variation, as it keeps the options already set for Haml::Template.
Put this at the end of your haml initializer.
class Tilt::HamlTemplate
def prepare
options = #options.merge(:filename => eval_file, :line => line)
# Use same options as Haml::Template
options = options.merge Haml::Template.options
#engine = ::Haml::Engine.new(data, options)
end
end

Related

Rails App to Angular: HAML + Rails Helpers

I'm trying to move my full-stack rails app over to Angular a page at a time. I'm using ui-router (https://github.com/angular-ui/ui-router) and angular-rails-templates (https://github.com/pitr/angular-rails-templates). I assumed the nghaml extension would allow me to continue to use rails helpers such as link_to, paths, etc. in my haml so just copied and pasted my haml page into the template; in an ideal world I would now be at a point where one page was being served client-side and every other page (including the ones it's linked to) were still being served server-side. Instead, I'm getting errors such as:
undefined local variable or method `dashboard_patients_path' for #<Object:0x007fc87865cff0>
and link_to, etc.
I thought this (angularjs with client side haml) would be a solid solution, specifically sharpper's response since it seemed directly applicable.
module CustomHamlEngine
class HamlTemplate < Tilt::HamlTemplate
def evaluate(scope, locals, &block)
scope.class_eval do
include Rails.application.routes.url_helpers
include Rails.application.routes.mounted_helpers
include ActionView::Helpers
end
super
end
end
end
Rails.application.assets.register_engine '.haml', CustomHamlEngine::HamlTemplate
However, even after restarting the server, no dice.
Thoughts?
Got stuck with the same problem and found a solution after investigating angular-rails-templates, attentively reading their documentation and using the solution proposed by sharpper in angularjs with client side haml.
angular-rails-templates needs to recreate a mimeless version of the haml engine. So they extend the classes that are registered with Tilt instead of using the engines that were added to the asset pipelines. Therefore the new CustomHamlEngine that we create and register with the asset pipeline is never used by angular-rails-template. What we need to do instead is to register the engine with Tilt.
Create a file called angular_rails_templates.rb in the config/initializers folder and put this code in it.
# config/initializers/angular_rails_templates.rb
module CustomHamlEngine
class HamlTemplate < Tilt::HamlTemplate
def evaluate(scope, locals, &block)
scope.class_eval do
include Rails.application.routes.url_helpers
include Rails.application.routes.mounted_helpers
include ActionView::Helpers
end
super
end
end
end
Tilt.register CustomHamlEngine::HamlTemplate, '.haml'
That will override the usual .haml engine with the one we just created. Angular-rails-templates will then process your haml file and it will support the rails helpers as well as the path helpers.
Don't forget to restart the server after including the file.

How do I use two different simple_form.rb initializer files?

Problem
This is a simple question, I've looked around spree forums, plataforma tec forums and SO with no success.
We want to use two separate simple_form configurations, one for our main application and another for a spree engine store we have mounted on a specific url.
More detailed Explanation
Currently in we're developing an application using the spree engine. This means that the spree engine is mounted on a specific url and is activated by going to mysite.com/store, for example.
Now, on the main app, we're using a different set of assets than those of the spree store. Our original simple_form.rb initializer was created specifically for these assets.
Here's where it gets interesting.
Within the spree engine, we're developing a new form using simple_form as well. It works fine, but it's using the simple_form.rb file of our main app, which uses the main app's css tags and markup.
We need to modify the simple_form.rb file to actually use the spree template's css in order for things to display correctly.
Possible solutions?
Ideally we should have a simple_form.rb file for the spree engine and one for the main app, but I haven't figured out a straight forward way of doing this...
My other idea was to have some sort of conditional in the simple_form.rb file for it to load one set of options when we're on the main app and another set of options when in the spree store... maybe checking the url?
Ok, so apparently it is pretty obvious how to have separate configurations for simple_form.
Everything goes into a single simple_form.rb initializer. the only thing that changes is the config.wrapper.
SimpleForm.setup do |config|
# Wrappers are used by the form builder to generate a
# complete input. You can remove any component from the
# wrapper, change the order or even add your own to the
# stack. The options given below are used to wrap the
# whole input.
config.wrappers :default, :class => :input do |b|
# config goes here
end
config.wrappers :special, :class => input do |b|
# special config goes here
end
config.default_wrapper = :default
end
Then in your code, if you want to use the :special wrapper just write in your input like so
f.input :name, :wrapper => :special
you can find more info here
Custom Wrappers

Disable Rails 3.1 asset pipeline for images only?

I'm upgrading a Rails 3 app to 3.2 and setting up the asset pipeline. It's great for css/js but I don't really see the point in using it for images, and unfortunately I have css with a ton of references /images/*.png and the like.
Is there a way to disable the asset pipeline just for images so image_tag("x.png") will go back to returning <img src="/images/x.png"> instead of <img src="/assets/x.png">? Thanks!
You can monkey-patch ActionView::Base, try this in rails console:
helper.image_path "foo" #=> "/assets/foo"
module OldImagePath
def image_path(source)
asset_paths.compute_public_path(source, 'images')
end
alias_method :path_to_image, :image_path
end
ActionView::Base.send :include, OldImagePath
helper.image_path "foo" #=> "/images/foo"
You can place this in an initializer for example. By default ActionView::Base includes ActionView::Helpers::AssetTagHelper and Sprockets::Helpers::RailsHelper which both define image_path but the latter take precedence. I'm including my own module which take precedence over all of them (the code inside is taken from ActionView::Helpers::AssetTagHelper).
Although, it makes sense to use asset pipeline for images too. They get hash sum in their filenames so that they can be cached forever on the client side without asking the server whether the file was changed.
Have a look at this gem:
https://github.com/spohlenz/digestion, it should do what you need :).
Otherwise you can move the assets you don't want included in the asset pipeline from app/assets back into public (e.g. public/images). Everything should work as you expect without the need for a gem.

generate nofollow links in RDiscount output

My rails app is using RDiscount to generate HTML from user-supplied markdown text, and I noticed that the anchor tags don't have rel="nofollow". This is a big issue for me as my app is open to the public. Is there a way to enable nofollow links, or are there better solutions?
Thanks!
I think this is possible only with Kramdown, which is a ruby Markdown parser with extended syntax. You would do that then as shown in the link:
[link](test.html){:rel='nofollow'}
In the mean time, I am using this hack, by re-parsing the RDiscount output and add a rel="nofollow" to each anchor:
def markdown(input)
html = RDiscount.new(input).to_html
doc = Nokogiri::HTML::DocumentFragment.parse(html)
doc.css("a").each do |link|
link['rel'] = 'nofollow'
end
doc.to_html
end
Though I think this should really be handled by the markdown parser.
I needed to do something similar, add target="_new" to all links. Solved it using Kramdown and a custom Kramdown::Converter::Html class.
Define a Kramdown::Converter::Html subclass (kramdown/converter/my_html.rb in some autoload path)
class Kramdown::Converter::MyHtml < Kramdown::Converter::Html
def convert_a(el, indent)
el.attr['target'] = '_new'
super
end
end
I also have a view helper in app/helpers/application_helper.rb
def markdown(str)
Kramdown::Converter::MyHtml.convert(Kramdown::Document.new(str).root)[0].html_safe
end
Ideally it should be possible to just use Kramdown::Document.new(str).to_my_html.html_safe but I can't get it to work in rails development mode as Kramdown uses const_defined? to see if a converter is available and that does not trigger the autoloader. Please comment if you know how to fix this.
There is an open feature request on RDiscount to support modifying links in this fashion.
It is scheduled for one of the upcoming RDiscount 2.1.5.x releases.

Ruby on Rails: How do I specify a non-relative path to a layout when calling render?

(Rails version 2.3.2)
By default the :layout parameter for render takes a relative path and adds this to the default layout directory ("app/views/layout").
Eg:
render :file => '../resources/website/home_page.html.erb', :layout => '../../../../resources/website/layout'
"If no directory is specified for the template name, the template will by default be looked for in app/views/layouts/. Otherwise, it will be looked up relative to the template root."
-http://api.rubyonrails.org/classes/ActionController/Layout/ClassMethods.html
However, the above only works in development mode, and breaks in production, failing to find the template. Exception: ActionView::MissingTemplate
Either way, I would rather specify the direct path to a layout file.
(The idea is to keep the specified layout file separate from the main project views, in a plugin-like way.)
Is this possible?
I could temporarily (instance only) override the method "default_layout" in ActionController::Layout? (But im not sure how?)
Thanks for reading.
If you need to resolve layout per request, try:
class ApplicationController < ActionController::Base
layout :resolve_layout
# some definitions
protected
def resolve_layout
# some logic depending on current request
path_to_layout = RAILS_ROOT + "/path/to/layout"
return path_to_layout
end
end
I hope, that is what you need.
Probably the only good way to do this would be to make a constant in your environment.rb with the path for whatever box you're on. So something like
LAYOUT_PATH = '/var/www/templates'
The other option would be to keep the templates in the correct directory but use an svn external or the equivalent in your SCM of choice to keep that template directory up to date with all the other sites that use the same templates.
You can probably add to the controller view paths (see here) to allow your app to pick up templates from different directories. This could potentially also cure your other weird template paths.
If you want absolute paths, use RAILS_ROOT, as suggested here. If you want to share views from a plugin, you may also want to check out the rails-engines plugin.
But also remember that Rails (kind of intentionally) makes doing strange things hard. If you don't have a really strong reason to do otherwise, you'll enjoy a smoother ride by sticking to the defaults.

Resources