Rails app template is running code and thowing fits
I'm trying to create a Rails app template I have this block of code in there
file 'config/sass.rb', <<-RUBY
Sass::Engine::DEFAULT_OPTIONS[:load_paths].tap do |load_paths|
load_paths << "#{Rails.root}/app/assets/stylesheets"
load_paths << "#{Gem.loaded_specs['compass'].full_gem_path}/frameworks/compass/stylesheets"
end
RUBY
When I run 'rails new' with this template I get the following error:
undefined method `root' for Rails:Module (NoMethodError)
I'm new to app templates as well as this code block syntax. (What do you even call that <<-RUBY block? It's really hard to search for on google). It was my impression that it wouldn't be running any of the code inside the block so it开发者_Python百科 shouldn't be causing errors. What gives?
UPDATE: Let me add some more context:
I'm trying to modify the app template here: https://github.com/leshill/rails3-app/blob/master/app.rb I want add the code from this blog post: http://metaskills.net/2011/05/18/use-compass-sass-framework-files-with-the-rails-3.1-asset-pipeline/ so that I can have compass support in rails3.1
To elaborate on mu's point.
The <<-SOMESTIRING
syntax defines the beginning of a string. The string is terminated with SOMESTRING
(at the start of the line)
For example you see this a lot
string = <<-EOF
Hey this is a really long string
with lots of new lines
EOF
string # => " Hey this is a really long string\n\n with lots of new lines\n"
In this case the RUBY
is to signify that this is ruby code (that will be evaluated). You have to remember that when inside a string the #{ruby_code}
escape syntax will evaluate the ruby_code given and insert the result into the string.
So to get around this you can do something like,
irb >> s = <<-RUBY
"#{'#{Rails.root}'}/app/assets/stylesheets"
RUBY
#=> ""\#{Rails.root}/app/assets/stylesheets"\n"
Here we break out of the string using #{}
and then use the single quotes to tell ruby that we don't want the #{Rails.root}
evaluated.
EDIT: I was thinking more about this, and realized this is equivalent and a little cleaner
irb >> s= <<-RUBY
Rails.root.to_s + "/app/assets/stylesheets"
RUBY #=> "Rails.root.to_s + "/app/assets/stylesheets"\n"
This way we don't have to worry about escaping at all : )
You are asking the "rails new" command to create a file and passing a block of content using a "heredoc" (signaled by the <<-SOMESTRING
syntax). More about heredoc:
http://en.wikipedia.org/wiki/Here_document#Ruby
The parser will treat the content just like a Ruby string surrounded by doublequotes and attempt to substitute any string enclosed by #{}
. It fails because it can't find a variable named Rails.root
.
You can avoid the substitution behavior (have the content treated like a Ruby string surrounded by singlequotes) by using single-quote-style-heredoc. Surround the heredoc signal with singlequotes:
file 'config/sass.rb', <<-'RUBY'
Sass::Engine::DEFAULT_OPTIONS[:load_paths].tap do |load_paths| load_paths << "#{Rails.root}/app/assets/stylesheets" load_paths << "#{Gem.loaded_specs['compass'].full_gem_path}/frameworks/compass/stylesheets" end
RUBY
Since you're creating Rails app template for a starter app, it might be helpful to look at the
Rails 3.1 Application Templates from the Rails Apps project on GitHub.
The project provides good examples of app templates plus documentation (be sure to take a look at Thor::Actions and Rails::Generators::Actions).
精彩评论