I'm trying to get rails to push the contents of a directory to Haml (as an array of strings) and render them as links with their filenames as the linked text, yet can't figure out how to pass multiple instance variables to my Haml file. Here's my controller code:
class FilesController < ApplicationController
def index
@dir = Dir.new('/Users/userName/Code/RailsTest/public/');
@files = Dir::entries('/Users/userName/Code/RailsTest/public/');
@fileNames = @files;
for file in @files
file = @dir.path + '/' + file
end
respond_to do |format|
format.html # index.html.haml
#format.xml { render :locals {:files => @files, :fileNames: @fileNames} }
format.xml { render :xml => @files }
end
end
end
and my Haml file:
%h1 Files
%p This will eventually list the files in our upload directory
- @files.each do |file|
%a(href=file) file
Thanks for any help that can be given!
Edit: My controller method now contains
@dir = Dir.new('/Users/chronon/DEsktop/RailsNexus/public');
@files = Dir::entries('/Users/chronon/DEsktop/RailsNexus/publ开发者_如何学Cic');
@fileNames = @files;
@files.map! do |file|
{:path => "#{@dir.path}/#{file}", :filename => file}
end
respond_to do |format|
format.htm
end
And both index.html.haml and _file_link.html.haml are as nzifnab suggested. However, I now get 'Cannot convert symbol into Integer" error in my _file_link file.
the contents of both haml files are
%h1 Files
%p This will eventually list the files in our upload directory
= render :partial => 'files/file_link', :collection => @files, :as => :file
= link_to(:file[:path], :file[:filename])
(I had to change 'file' to ':file' for the render to work properly. Based that off of Rails Guides)
There are two ways to do this: Rendering it as a partial, or rendering a normal output template. If you render it as a partial you will be able to pass a :locals options hash that you can use to grab the variables. If you render a normal haml file then you will need to use instance variables for the data.
I would change the for loop in your controller to this:
@files.map! do |file|
{:path => "#{@dir.path}/#{file}", :filename => file}
end
Edit: Just realized you may be un-used to the .map! method. It will go through each entry in @files once, and change the value of it to whatever is the last line in the block. if you use .map and not .map! then the method will return a new array consisting of those values.
That's just a little more ruby-like, and I'm not 100% sure if the for loop you're using is altering the value by reference like you intend it to. Again maybe yours is fine... but I like the ruby-like methods like Array.map, Array.each etc instead of the for syntax, and this gets you all the data you need for each object in a nice Hash.
Your haml file can be changed as follows:
index.html.haml
%h1 Files
%p Something exciting
= render :partial => 'files/file_link', :collection => @files, :as => :file
This will render the file files/file_link.html.haml
once for each object found in the @files
array, and save that object in the local variable file
as specified by the :as =>
option.
Then you can have this file:
_file_link.html.haml
= link_to(file[:path], file[:filename])
Any instance variables you define in your controller will automatically be available in the view. If for whatever reason you wanted to make the object in the view a local variable instead, you would have to render the view as a partial instead of a full view, I believe. Although it may work to do this, I'm not 100% sure.:
format.html{ render :action => 'index', :locals => {:files => files} }
However this isn't really good practice. It's typical to just use the instance variables from the controller straight in the view. Hopefully I answered your question somewhere in here :) (the format.html
you have with no options or parameters is sufficient for the view code I posted above).
EDIT:
you were correct to change the render :partial to, :as => :file
(symbol here, I updated it above). However, what it does is send each item in the @files
array as a new local variable named file
to the partial. So your partial should still say:
= link_to(file[:path], file[:filename])
Also keep in mind that you don't need your @fileNames
instance variable anymore. the .map!
and hash fixed that issue for you.
To clarify, after you called @files.map! do
... etc etc, your data structure should look something like this:
@files = [
{:path => "my/path/1/filenamex", :filename => "filenamex"},
{:path => "my/path/2/filenamey", :filename => "filenamey"},
{:path => "my/path/3/filenamez", :filename => "filenamez"}
]
Thus, when you send the variable to render :partial =>
It is going to render once for each of those hashes. The first render, it will set the file
variable within _file_link.html.haml to this:
{:path => "my/path/1/filenamex", :filename => "filenamex"}
And it will go through it three times for each hash value.
I hope you understand what's going on :)
Think this is what you want
@myfiles = [];
for file in @files
@myfiles << { :file => @dir.path + '/' + file, :filename => file}
end
respond_to do |format|
format.html
end
精彩评论