views:

189

answers:

1

I'm making a Rails template file as introduced below:

I have a big file I want to make, so instead of doing:

file "bigfile.txt", <<-EOF
  content of the file...
EOF

I want to read the content from another file. What I have now is:

file "public/stylesheets/sass/960.sass", File.read(File.expand_path(File.join(File.dirname(__FILE__), "960.sass")))

The file is located in the same directory as the rails template file. The problem is: when I try to make a rails app with the template (i.e., rails new_app -m rails_template/rails_template.rb, I get the following error:

The template [rails_template/rails_template.rb] could not be loaded. Error: (eval):129:in `read': No such file or directory - /Users/myusername/Desktop/new_app/960.sass

This is all because __SELF__ is not working the way I expected. I expect __SELF__ to be the template file itself, but in reality, __SELF__ is poiting to the root of the app or somewhere else.

Is there a way to load file in a rails template?

+2  A: 

There is no problem reading a file from within a template. If you were to hard code the path to the source copy of 960.sass then it would work fine.

As you suspect the problem lies with the use of __FILE__. The reason is that if you look in rails-2.3.4\lib\rails_generator\generators\applications\app\template_runner.rb you will see that load_template loads the template into a string and then executes it using instance_eval:

def load_template(template)
  begin
    code = open(template).read
    in_root { self.instance_eval(code) }
  rescue LoadError, Errno::ENOENT => e
    raise "The template [#{template}] could not be loaded. Error: #{e}"
    end
end

Hence when your code executes the context is an eval block and __FILE__ won't point to your file.

The good news is that the template parameter passed to load_template (containing the path to your template) is a local variable at the point when instance_eval is called and so is available from the code inside your template. If instead you just do:

File.dirname(template)

then it should work. Be aware though that you are then tying your code to the current implementation of load_template, which could change in the future.

mikej