Adding HAML to the Rails asset pipeline - ruby-on-rails-3

I would like to serve client side templates that have been pre-processed through HAML. I have tried using the haml_assets gem and adding the following code to an initializer:
Rails.application.assets.register_engine ".haml", Tilt::HamlTemplate
Both of these methods serve the raw HAML and not compiled HAML when I access the asset. How can I add HAML to the pipeline?

Just to clear things up, since I find the current answers a bit irritating (led me to the right direction though)
It works, if i have this line in an initializer file:
# config/initializers/haml_assets.rb
Rails.application.assets.register_engine '.haml', Tilt::HamlTemplate
Throw your haml files into the assets folder, for example:
# app/assets/templates
Do not use the haml_asset gem though!

The following code in application.rb works for me in Rails 3.2 (both in development and in production after pre-compilation):
require 'haml'
config.assets.paths << Rails.root.join("app", "assets", "templates")
class HamlTemplate < Tilt::HamlTemplate
def prepare
#options = #options.merge :format => :html5
super
end
end
config.before_initialize do |app|
require 'sprockets'
Sprockets::Engines #force autoloading
Sprockets.register_engine '.haml', HamlTemplate
end
This allows you to put you templates in app/assets/templates named with the suffix .html.haml (you need the .html in there or else .htm files get generated instead of .html in the pre-compilation process).

This works for me:
# app/assets/javascripts/test.html.haml
%p hello
# config/initializers/haml_template.rb
Rails.application.assets.register_mime_type 'text/html', '.html'
Rails.application.assets.register_engine '.haml', Tilt::HamlTemplate
This works for http://127.0.0.1:3000/assets/test.html.haml
Rails.application.assets is a Sprockets::Environment.
See here for API reference:
https://github.com/sstephenson/sprockets/blob/master/lib/sprockets/processing.rb
https://github.com/sstephenson/sprockets/blob/master/lib/sprockets/engines.rb

Using the same approach I've got:
%tr
%th
%a.action.link.show
%td
%td
returned as pure haml. But
%tr
%th
%a.action.link.show
%td cell 2
%td cell 3
was served as html chunk. So I think this is something with haml gem. You can force haml conversion with something like this:
%tr
%th
%a.action.link.show
%td &nbsp
%td &nbsp
Hope it helps...

Two of the previous answers here had to be combined before we had a full solution.
The following line works in development:
# config/initializers/haml_assets.rb
Rails.application.assets.register_engine '.haml', Tilt::HamlTemplate
But then fails on any precompile.
For asset-served haml to work after a precompile, we also needed these lines in application.rb:
require 'haml'
config.assets.paths << Rails.root.join("app", "assets", "templates")
class HamlTemplate < Tilt::HamlTemplate
def prepare
#options = #options.merge :format => :html5
super
end
end
config.before_initialize do |app|
require 'sprockets'
Sprockets::Engines #force autoloading
Sprockets.register_engine '.haml', HamlTemplate
end

With sprockets 3 and 4
# in /config/initializers/haml.rb
Rails.application.config.assets.configure do |env|
env.register_mime_type "text/haml", extensions: %w(.haml .html.haml)
env.register_transformer 'text/haml', Tilt::HamlTemplate.default_mime_type, Tilt::HamlTemplate
end

Related

rails3 monkey-patch generator

I want to monkey-patch the rspec-rails generator to generates a _form.html_spec.rb template. I know how do that, but not where I should put this patch!
What I've done:
# rspec_generator_patch.rb
module Rspec
module Generators
class ScaffoldGenerator < Base
def generate_views_specs_with_form *args, &block
generate_views_specs_without_form
copy_view :_form
end
alias_method_chain :generate_views_specs, :form
end
end
end
Where I put this file? Thank you.
EDIT:
Ok, I think problem is almost solved. Instead of monkey-patch, I've inherited the specific generators and edited the method. There's the solution:
# lib/generators/rspec_modded/scaffold/scaffold_generator.rb
require 'generators/rspec/scaffold/scaffold_generator.rb'
module RspecModded
module Generators
class ScaffoldGenerator < Rspec::Generators::ScaffoldGenerator
def generate_view_specs
super
copy_view :_form
end
end
end
end
If I do rails g rspec_modded:scaffold is in list and actually work if called manually (rails g rspec_modded:scaffold test).
# config/application.rb
# ...
config.generators do |g|
g.test_framework :rspec_modded, :fixture => false, fixture_replacement: nil
g.fallbacks[:rspec_modded] = :rspec
end
For what I know, every hook_for :test_framework should call rspec_modded generator and rspec should manage the rest (fallbacks). But it doesn't work: for some reason the unit_test generator kick in! What the matter? I really don't understand...
You can put your monkey patch anywhere, as long as it gets loaded. With rails, you'd usually put it in the /lib folder.

Rails 3: PDF generation with wicked_pdf suddenly does not work anymore ? [undefined method `virtual_path']

Our platform has been online for a while and working just fine. Our customers are able to download their invoices in PDF format just fine.
We've been working on a upgrades for a few month, and just today we noticed that "suddenly" non of our PDF generation with wicked_pdf and wkhtmltopdf no longer worked...
I have absolutely no idea why, I checked everything I could think of:
- routes
- initializers
- gems
- etc.
Everything seems to be fine, same as the actual only version.
We have not changed Rails or Ruby version. Everything is pretty much the same:
- Ruby 1.8.7 REE
- Rails 3.0.10
The error we are getting is:
Rendered groups/clients/proforma.pdf.haml (103.4ms)
Sent data toto.pdf (2.7ms)
Completed 500 Internal Server Error in 6892ms
NoMethodError (undefined method `virtual_path' for text template:ActionView::Template::Text):
app/controllers/groups/clients_controller.rb:980:in `proforma'
app/controllers/groups/clients_controller.rb:976:in `proforma'
lib/include/flash_session_cookie_middleware.rb:16:in `call'
lib/include/flash_session_cookie_middleware.rb:16:in `call'
The controller looks like:
def proforma
#request = WireRequest.where(:_id => params[:id], :status => :pending).first
respond_to do |format|
format.html {render :layout => false}
format.pdf do
unless #request.nil?"
render(:pdf => "PROFORMA_#{#request.invoice_num}", :layout => 'pdf')
end
end
end
end
Any ideas of what could be going wrong? I have no more ideas :(
I already had this kind of issue using the new relic rpm for developers.
I forked the gem here.

spec view helper in gem

I'm writing a rails 3 railtie which defines some view helpers. Now I wonder how to spec the view helper methods because I cannot instantiate a module. I already searched and read a lot, but I just couldnt get it working.
view_helper_spec.rb
require 'spec_helper'
module MyRailtie
describe ViewHelper, :type => :helper do
describe "style_tag" do
it "should return a style tag with inline css" do
helper.style_tag("body{background:#ff0}").should ==
body{background:#ff0}
EOT
end
end
end
end
It always complains that "helper" is not defined. It seems that :type => :helper doesn't to anything.
The gemspec requires the rspec and the rspec-rails gems in development/ test mode.
I think I found the solution (it's painfully obvious once you think about it). Just stick this at the top of your spec:
require 'action_view'
require 'active_support'
include ViewHelper
include ActionView::Helpers

rails3-amf - to_amf method not found on ActiveRecord objects

I am using the rails3-amf gem by warhammerkid in my Rails 3 / Flex 4 project.
AFAIK, I have correctly followed the "Getting Started" instructions from the GitHub page.
I have added the gem lines to my Gemfile.
I have installed the gems using bundle install.
From my Flex application, I will be making the RemoteObject call to the index action in the ManageMySchool::GradesController file. This is the code in the app/controllers/manage_my_school/grades_controller.rb file:
class ManageMySchool::GradesController < ApplicationController
respond_to :html, :amf
def index
#grade = Grade.first
respond_with(#grade) do |format|
format.amf { render :amf => #grade.to_amf }
end
end
end
The name of the model which is to be serialized is called Grade in both the Rails project (app/models/Grade.rb) and the Flex project (Grade.as with a RemoteAlias set as Grade). In the config/application.rb file, I have done the class mapping this way:
config.rails3amf.class_mapping do |m|
m.map :as => 'Grade', :ruby => 'Grade'
end
And I have done a parameter mapping this way:
config.rails3amf.map_params :controller => 'ManageMySchool::GradesController', :action => 'index', :params => [:authenticity_token]
Problem
Now, when I run the server and make the RemoteObject call from Flex, I get a to_amf undefined method error for the Grade model.
If I change Grade.first to Grade.all, #grade would have an array of Grades. But the undefined method error message still mentions the Grade model. This means that the to_amf method is working for the Array class but not for the ActiveRecord model.
Why is this? What am I doing wrong?
Is there something I have to do to "enable" the rails3-amf gem for ActiveRecord models?
I would appreciate any insights. Thanks!
Update
#warhammerkid: Here is the output of Grade.ancestors as seen in rails console.
ree-1.8.7-2011.03 :006 > puts Grade.ancestors
Grade
ActiveRecord::Base
Paperclip::CallbackCompatability::Rails3::Running
Paperclip::CallbackCompatability::Rails3
Paperclip::Glue CanCan::ModelAdditions
Authlogic::ActsAsAuthentic::ValidationsScope
Authlogic::ActsAsAuthentic::SingleAccessToken
Authlogic::ActsAsAuthentic::SessionMaintenance
Authlogic::ActsAsAuthentic::RestfulAuthentication::InstanceMethods
Authlogic::ActsAsAuthentic::RestfulAuthentication
Authlogic::ActsAsAuthentic::PersistenceToken
Authlogic::ActsAsAuthentic::PerishableToken
Authlogic::ActsAsAuthentic::Password
Authlogic::ActsAsAuthentic::MagicColumns
Authlogic::ActsAsAuthentic::Login
Authlogic::ActsAsAuthentic::LoggedInStatus
Authlogic::ActsAsAuthentic::Email
Authlogic::ActsAsAuthentic::Base
ActiveRecord::Aggregations
ActiveRecord::Transactions
ActiveRecord::Reflection
ActiveRecord::Serialization
ActiveModel::Serializers::Xml
ActiveModel::Serializers::JSON
ActiveModel::Serialization
ActiveRecord::AutosaveAssociation
ActiveRecord::NestedAttributes
ActiveRecord::Associations
ActiveRecord::AssociationPreload
ActiveRecord::NamedScope
ActiveModel::Validations::Callbacks
ActiveRecord::Callbacks
ActiveModel::Observing
ActiveRecord::Timestamp
ActiveModel::MassAssignmentSecurity
ActiveRecord::AttributeMethods::Dirty
ActiveModel::Dirty
ActiveRecord::AttributeMethods::TimeZoneConversion
ActiveRecord::AttributeMethods::PrimaryKey
ActiveRecord::AttributeMethods::Read
ActiveRecord::AttributeMethods::Write
ActiveRecord::AttributeMethods::BeforeTypeCast
#<Module:0x1028356f0> ActiveRecord::AttributeMethods::Query
ActiveRecord::AttributeMethods
ActiveModel::AttributeMethods
ActiveRecord::Locking::Optimistic
ActiveRecord::Locking::Pessimistic
ActiveRecord::Validations
ActiveModel::Validations::HelperMethods
ActiveModel::Validations
ActiveSupport::Callbacks
ActiveModel::Conversion
ActiveRecord::Persistence Object
PP::ObjectMixin Base64::Deprecated
Base64
ActiveSupport::Dependencies::Loadable
Kernel
Note that only ActiveModel::Serialization is there. No mention of Rails3AMF.
Does this mean I have to do something special to load the Rails3AMF module for the ActiveRecord models?
I am using Rails 3.0.5 with the latest version of ree. The gems are all contained in a gemset managed using rvm.
Update 2
If I remove the to_amf in the render :amf line, then I get the following error:
Grade Load (0.3ms) SELECT `grades`.* FROM `grades` LIMIT 1
Completed 200 OK in 195ms (Views: 0.1ms | ActiveRecord: 0.8ms)
Sending back AMF
NoMethodError (You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.last):
Rendered /Users/anjan/.rvm/gems/ree-1.8.7-2011.03#rb/gems/actionpack-3.0.5/lib/> > action_dispatch/middleware/templates/rescues/_trace.erb (1.1ms)
Rendered /Users/anjan/.rvm/gems/ree-1.8.7-2011.03#rb/gems/actionpack-3.0.5/lib/> > action_dispatch/middleware/templates/rescues/_request_and_response.erb (2.8ms)
Rendered /Users/anjan/.rvm/gems/ree-1.8.7-2011.03#rb/gems/actionpack-3.0.5/lib/> > action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (13.6ms)
Started POST "/amf" for 127.0.0.1 at Fri Apr 15 17:03:34 +0530 2011
Sending back AMF
Update 3
If I manually add the line include Rails3AMF::Serialization at the top of the Grade.rb model file, then it all works. So, does this mean that I have to put this line in all my models?
I see that this is already being done in line numbers 40 - 42 in the lib/rails3-amf/serialization.rb file of the gem:
# Hook into any object that includes ActiveModel::Serialization
module ActiveModel::Serialization
include Rails3AMF::Serialization
end
Why isn't this working? Should I force-load the gem when my application initializes or something?
Thanks!
Update 4 - Solved by this workaround
Okay, I just ended up adding this code block in an initializer:
class ActiveRecord::Base
include Rails3AMF::Serialization
end
And it is working.
#warhammerkid - Thanks for the help.
Rails3AMF::Serialization, the module that adds the to_amf method, is included in ActiveModel::Serialization when Rails3-AMF loads. If it's somehow not being included even though the code is running and ActiveModel::Serialization is one of your model's ancestors, then the simplest solution is just to add "include Rails3AMF::Serialization" at the top of your model implementation. I've never tried gem sets before, but it might be an issue with them, as everything works correctly using Bundler.
As an aside, feel free to post a bug to https://github.com/warhammerkid/rails3-amf/issues.

How can I automatically render partials using markdown in Rails 3?

I want to have some of my partials as markdown snippets. What is the easiest way to render them using the standard rails erb templating?
Ideally, I'd like to do something like this:
If I have a partial in app/views/_my_partial.md.erb:
My awesome view
===============
Look, I can **use** <%= language %>!
which I reference from a view like so:
<%= render "my_partial", :language => "Markdown!" %>
I want to get output that looks like this:
<h1>My awesome view</h1>
<p>Look, I can <strong>use</strong> Markdown!</p>
Turns out, the Right Way (tm) to do this is using ActionView::Template.register_template_handler:
lib/markdown_handler.rb:
require 'rdiscount'
module MarkdownHandler
def self.erb
#erb ||= ActionView::Template.registered_template_handler(:erb)
end
def self.call(template)
compiled_source = erb.call(template)
"RDiscount.new(begin;#{compiled_source};end).to_html"
end
end
ActionView::Template.register_template_handler :md, MarkdownHandler
If you require 'markdown_handler' in your config/application.rb (or an initializer), then any view or partial can be rendered as Markdown with ERb interpolation using the extension .html.md:
app/views/home/index.html.md:
My awesome view
===============
Look, I can **use** <%= #language %>!
app/controllers/home_controller.rb:
class HomeController < ApplicationController
def index
#language = "Markdown"
end
end
Not a pure markdown solution but you can use HAML filters to render markdown, as well as other markup languages.
For example, in app/views/_my_partial.html.haml:
:markdown
My awesome view
===============
Look, I can **use** #{language}!
Have found way not to use haml in such situation.
in views/layouts/_markdown.html.erb
<%= m yield %>
in app/helpers/application_helper.rb
def m(string)
RDiscount.new(string).to_html.html_safe
end
in Gemfile
gem 'rdiscount'
So, in view you can call it like:
<%= render :partial => "contract.markdown", :layout => 'layouts/markdown.html.erb' %>
And contract.markdown will be formatted as markdown
I just released a markdown-rails gem, which handles .html.md views.
You cannot chain it with Erb though -- it's only for static views and partials. To embed Ruby code, you'd have to use tjwallace's solution with :markdown.
Piling on the solutions already presented, this is an interpolation-ary way in Rails 3 to render a pure Markdown file in a view from a partial without unnecessary indentation using Haml's :markdown filter and the RDiscount gem. The only catch is that your Markdown file is a Haml file, but that shouldn't matter for someone like a copy person.
In Gemfile:
gem 'rdiscount'
In app/views/my_page.html.haml
:markdown
#{render 'my_partial', language: 'Markdown!'}
In app/views/_my_partial.html.haml
My awesome view
===============
Look, I can **use** #{language}!
If you didn't need the :language variable passed in to the markdown file, you could do away altogether with your Markdown being a Haml file:
In app/views/my_page.html.haml
:markdown
#{render 'my_partial.md'}
In app/views/_my_partial.md
My awesome view
===============
Sorry, cannot **use** #{language} here!
Don't like those pesky underscores on your Markdown files?
In app/views/my_page.html.haml
:markdown
#{render file: 'my_markdown.md'}
In app/views/my_markdown.md
My awesome view
===============
Sorry, cannot **use** #{language} here!
Leveraged your answer to make a gem to render for GitHub Flavored Markdown in Rails (via HTML::Pipeline): https://github.com/afeld/html_pipeline_rails
Here is a version similar to #Jacob's but using Redcarpet.
module MarkdownHandler
def self.erb
#erb ||= ActionView::Template.registered_template_handler(:erb)
end
def self.call(template)
options = {
fenced_code_blocks: true,
smartypants: true,
disable_indented_code_blocks: true,
prettify: true,
tables: true,
with_toc_data: true,
no_intra_emphasis: true
}
#markdown ||= Redcarpet::Markdown.new(Redcarpet::Render::HTML, options)
"#{#markdown.render(template.source).inspect}.html_safe"
end
end
ActionView::Template.register_template_handler :md, MarkdownHandler
Full credit to lencioni who posted this in this gist.
And if you'd like to evaluate erb:
erb = ERB.new(template.source).result
#markdown ||= Redcarpet::Markdown.new(Redcarpet::Render::HTML, options)
"#{#markdown.render(erb).inspect}.html_safe"
You can use embedded Markdown in Rails 5. Embedded Markdown is based on the solution provided by Jacob above
Add these to your application's Gemfile:
gem 'coderay' #optional for Syntax Highlighting
gem 'redcarpet'
gem 'emd'
bundle install.
Then create a view app/view/home/changelog.html.md and paste your markdown in that .md file.
Generate a home controller using the following command
rails generate controller home
Add the following line to your route.rb:
get '/changelog', :to 'home#changelog'
That's all. Visit http://localhost:3000/changelog to see your rendered markdown
Source: http://github.com/ytbryan/emd