开发者

Passing multiple variables to a Haml file within Rails?

开发者 https://www.devze.com 2023-02-15 05:25 出处:网络
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 multip

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
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号