render_to_string
Rendering a view in Rails to a String
This is old hat for pros, but this is such a useful method that I wanted to bring it up for anyone googling for this functionality (as I was months back).
Occasionally you'll want to render something in rails and keep the result in a string (to save into a db or file or to display later) rather than displaying it immediately. If you try to make a call to render and then go about your business redirecting or displaying another view you'll get a wonderful ActionController::DoubleRenderError telling you "Can only render or redirect once per action". You want to use render_to_string.
Example: rendering a haml template that has been loaded into template_content
rendered_result = render_to_string( :inline => template_content,
:type => :haml,
:locals => { :blah => @blah }
)
Write your Typo posts in Haml - A TextFilter plugin 6
Update #1: This plugin is now hosted on rubyforge. Please see the official HamlFilter plugin page and the rubyforge page
Update #2: This plugin is mentioned (and slightly mocked) on the Rails Envy Podcast. I've long enjoyed the Rails Envy Podcasts, so I appreciate the nod and joke.
Haml (HTML Abstraction Markup Language) is awesome. If you don't know just how awesome Haml is, you need to check it out asap. It'll speed up your templating dramatically.
Typo is also awesome. As a typo noob I discovered that sadly the two don't play well with each other when it comes to writing posts. I wanted to type my blog posts in Haml. And now I'm in luck and you are too, because this post is written in 100% Haml.
Introducing the Haml textfilter for Typo
I'm still new to Typo, so the packaging and install is ... well, there isn't any. That will hopefully change soon, but until then, you can infuse your typo blog with Haml-y goodness by doing the following.
- sudo gem install haml
- Download typo_textfilter_hamlfilter-0.1.tar and extract the folder to /your_typo_install/vendor/plugins
-
Run the following sql against your typo database
insert into `text_filters` (`name`, `description`, `markup`, `filters`, `params`) values('hamlfilter','HamlFilter','hamlfilter','--- \r\n- :hamlfilter','--- {}\r\n'); - Restart your typo server
- Via the typo Administration page, select Settings->Write and then select HamlFilter as your Article Filter. You can now do nifty stuff like
- Do not, I repeat, do not choose HamlFilter as your comment markup. If you do so, you're subjecting yourself to all kinds of malicious attacks.
='Hi!' * 10and get
Hi!Hi!Hi!Hi!Hi!Hi!Hi!Hi!Hi!Hi!
=Time.nowand get
Thu March 07 14:25:55 -0500 2008Haml evaluates your ruby code as expected. Because of this, you can do some neat things, but if you're not careful and allow HamlFilter to control your comments, you're in trouble:
After following these steps, everything should work as expected*. If your post is non-Haml-ized, there's probably a flaw in your spacing somewhere -Haml loves proper whitespace. You may want to write posts in your favorite text editor or something more Haml-friendly. A small price to pay for being free to Haml in Typo.
*One more note: Currently, to accomplish typo magic using things like <typo:code>, you'll need to use Haml's :preserve function like so:
:preserve
<typo:code lang="ruby">
class Person
attr_accessor :name
#alias for readability joy
alias knows? respond_to?
def initialize(name)
@name = name
end
end
</typo:code>
gives you
class Person
attr_accessor :name
#alias for readability joy
alias knows? respond_to?
def initialize(name)
@name = name
end
end
Enjoy and check back for updates as I formalize this thing. I'm hanging out in #typo on freenode trying to figure out how to better implement this, so hopefully I'll have a better solution soon.
Firefox highlight search quirk & Gmail - A Cautionary Tale
Imagine you're writing someone about a possible job using your fancy Google Apps for Your Domain gmail app. As you're proofreading you notice you've inconsistently capitalized a specific proper noun. Oops. No worries, right, this is what Ctrl-F is for... But if you click highlight when searching your email text, make sure you unclick it before sending... otherwise you end up actually sending an email with highlighted text and, undoubtedly, looking foolish.
Good game, firefox, you're too helpful.
Monkey Patching Ruby, just like in The Matrix - Whoa! 4
Update: in the comments, Eric Anderson reminds us that the common way to do this on the class-level is through mixins. You can read a good tutorial on mixins here.
Ruby has open classes. This means that your classes can learn to do new things or learn to do old things differently via monkey patching. This can be both a good thing or a bad thing depending on how the programmer chooses to use or abuse the feature.
To give an example of the openness of ruby classes, consider the following person class:
class Person
attr_accessor :name
#alias for readability joy
alias knows? respond_to?
def initialize(name)
@name = name
end
def action(out)
puts "*#{name} #{out}*"
end
def say(out)
puts "#{name}: #{out}"
end
def assert_knowledge(method)
say 'I ' + ( self.knows?(method) ? 'know ' : 'don\'t know ' ) + method.to_s + '. '
end
end Kinda boring... very limited functionality. Let's imagine that we suddenly find out we're living in The Matrix. Yikes. Ok, we're over the shock. Now we're out of the matrix and someone has plugged a cord into the back of our head and wants to use some crazy disks to teach us things.
class MartialArtsLearningTape
def teach(person)
def person.kung_fu
# ...
action 'KA-POW\'z!'
end
def person.ju_jitsu
# ...
action 'HI-YA\'s!'
end
# ...
end
end The MartialArtsLearningTape class can be used to modify a Person to give them new abilities (methods). Consider the following summary of the plot of The Matrix.
keanu = Person.new('Thomas Anderson')
keanu.assert_knowledge(:kung_fu)
keanu.action "gets unplugged from the martix"
keanu.name = 'Neo'
MartialArtsLearningTape.new.teach(keanu)
keanu.assert_knowledge(:kung_fu)
laurence = Person.new('Morpheus')
laurence.say 'Show me. '
keanu.say "self.methods.grep(/kung_fu/)\n=> #{keanu.methods.grep(/kung_fu/)}"
laurence.say 'uh....'
keanu.kung_fu When you run the matrix.rb script you get...
$ ruby matrix.rb Thomas Anderson: I don't know kung_fu. *Thomas Anderson gets all matrix-ized* Neo: I know kung_fu. Morpheus: Show me. Neo: self.methods.grep(/kung_fu/) => kung_fu Morpheus: uh.... *Neo KA-POW'z!*
A better way
There's a better way to code this. Let's create a method named unplug! which lets us give a Person learning abilities when they're unplugged from the matrix:
class Person
#...
def unplug!(new_name = @name)
action("gets unplugged from the matrix and is known as #{new_name}!")
@name = new_name
def learn(name, &block)
self.class.send(:define_method, name, &block)
end
end
end
class MartialArtsLearningTape
def teach(person)
person.learn(:kung_fu) { action 'KA-POW\'z!' }
person.learn(:ju_jitsu) { action "HI-YA\s!" }
# ...
end
end To see this in action, check out matrix2.rb
define_method is private, so we have to put in a helper method (learn) to use it in a friendly way. For other ways of teaching classes new tricks, check out chapter 11.3 of The Ruby Way, Second Edition, and specifically 11.3.5 for define_method.
What we've learned
- alias can be used to make our code a little more readable. Compare neo.respond_to?(:kung_fu) to neo.knows?(:kung_fu).
- Ruby classes are open and can learn new methods.
- Keanu Reeves can play characters other than Ted Theodore Logan and Evil Ted. Whoa.
Questions:
-
Isn't kung fu too awesome to not end in an exclamation point (i.e. neo.kung_fu!)?
I agree with you in principle... Programming Ruby: The Pragmatic Programmers' Guide, Second Edition offers the following:
Methods that are "dangerous," or modify the receiver, may be named with a trailing !
Well, kung fu is definitely potentially dangerous, but in this instance the receiver is self. Rather than modifying self, kung_fu is much more likely to modify the opponent's face. It really could it could go either way, but I'll stick with the "methods that modify self" approach since the opponent is not the receiver. -
Seriously, why are you aliasing "respond_to?"? Isn't that completely useless and wasteful?
Meh. There's no real reason except that its more readable and more natural in this context. respond_to? seems very mechanical while knows? is a little more human. Star Trek fans should appreciate the following proper use of respond_to?:
spot.respond_to?(:verbal_commands) # => false
