difficulty with an "include?" statement - ruby-on-rails

We need to verify that download links work. And because the files are quite large, we need to verify that we don't have outdated, useless files sitting in our download directory. So we have a download management page that validates that every database file_name has a file named the same in the download directory. The page then verifies that every file in our directory has a file_name in our database.
in the controller:
#documents = Document.find(:all, :order => "section asc, sub_section asc, position asc, name asc")
#files = Dir.glob("public/downloads/*").sort
FIRST VALIDATION: in my view to validate that there is a file for every document record in the database:
<% #documents.each do |d| -%>
<% if #files.include?("public/downloads/" + d.file_name)
clr = "Green"
else
clr = "Red"
end %>
... color coded print routine ...
<% end %>
SECOND VALIDATION: in my view to validate that every file has a document record in the datebase:
<% #files.each do |f| -%>
<% str = f.gsub(/^.*\//, '')
if #documents.include?(str)
clr = "Green"
else
clr = "Red"
end %>
... color coded print routine ...
<% end %>
with my small test document list, the printed database file_names match exactly with the file names printed from our download directory. however, the include test for the second validation is not working. i haven't been able to figure out why.
thanks!

This code:
if #documents.include?(str)
should look like this:
if #documents.detect{|doc| doc.file_name == str}

Instead of #documents.include?(str) use #documents.any? { |d| d.file_name == str}

The problem is that #documents is not a collection of file_names, it is a collection of Document instances. You should try something like this instead:
#documents.map(&:file_name).include?(str)
This will collect all file_names and then check if str matches any of them.

Related

Rails CSV exporting into excel produces special  and &amp characters

I have a rails project which is exporting some csv data into excel. On some instances excel is outputting special characters.
ex.
test 1 & test 2 & test 2
reads in excel as
test 1 & test 2 & test 2 
My default CSV encoding is set to UTF-8 and I have played around with a number of other encoding settings although none of them have seemed to solve this issue.
Here is where the csv gets generated.
<% headers = default_headers %>
<%= CSV.generate_line(headers).strip %>
<% #activities.each do |activity| %>
<% has_permission = #_controller.is_activity_permissioned_to_user?(activity, current_user) %>
<% row = activity_generate_csv_row_data(activity, headers, has_permission, preferences) %>
<%= CSV.generate_line(row).gsub(/\A""/,'').strip.html_safe %>
<% end %>
and in my controller.
format.csv {
headers['Content-Disposition'] = "attachment; filename=\"
{report_name}.csv\""
headers['Content-Type'] ||= 'text/csv'
}
Every solution i've tried has failed. I really just can't figure out how to fix this.
Try to concatenate a Byte Order Mark string with your CSV string, like:
BOM = "\uFEFF"
def some_csv_string_generating_func
...
return BOM + a_csv_string
end
This will make Excel show the CSV file correctly.
Also, I would advice against having all the CSV generation logic/code on the view, but on a helper class/module or the like.

Using puts in rails

I have this code in controller:
array = ["asd", "asd", "asd"]
#print = array.each do |i|
puts "Random text #{i}"
end
And now I want to print it in some pages view like show.html.erb:
<%= #print >
And I get this: ["asd", "asd", "asd"] But In controller I sayd to puts each object in array, but it is not doing it?
The puts method is for printing a string to the console. If you wanted to set each of the values of the array to a certain value in order to print it out later, you should use #map.
array = ['asd', 'asd', 'asd']
#print = array.map { |i| "Random text #{i}" }
Now, in your corresponding view, you should add:
<% #print.each do |val| %>
<%= val %>
<% end %>
puts prints to the stdout (standard output) that, in the majority of cases, corresponds to the console where you started the Rails server.
Check the console and you will find, in the middle of the request logs, also the result of the puts statement.
A better way to print out something from the console is to use the Rails logger, especially if you want such output to be logged in the logs in production.
Rails.logger.info "message"
Assuming it's just for debugging purpose, then it's fine to use puts (or p).
You should be doing the looping in your view. This helps maintain the separation between your application logic and your view code.
Controller
#array = ["asd", "asd", "asd"]
View
<% #array.each do |i|
<%= i %> # No need to use the puts method here
<% end %>
it seems that the variable #print is the array. The controller is run once per load of the page and then will output its contents at the end to the view. Plus, "puts" is for printing a string to the console. You should put the loop in question in the view like this:
<% #array.each do |i| %>
<%= i #>
<% end %>

Actions on an instance object passed to the view

I have an obj #files which sometimes contain one set of data(one file) and sometimes it contains many files.
I have a create.js.erb and this is what I do at the moment.
<% if #files.new_record? %>
alert("Failed to upload: <%= j #files.errors.full_messages.join(', ').html_safe %>");
<% else %>
$(".container").append('<div id="cfile"><%= j render(#files) %></div>');
<% end %>
Then I have a partial called _file.html.erb
<%= file.name %>
<%= file_.id %>
This all works fine but I'm running into problems trying to create a partial for different types of files.
I want to be able to do something like
if file.first.type == image # (Even If the come in groups they would be the same type so i just need one .type field from one of them.)
$(".different_container").append(render different partial here);
else if file.first.type == doc
$(".another_container").append(render another partial here);
How would I go about this?
Please ask if i haven't explained something clearly.
So the problem is that #files can be multiple items or a single item. Before you access it, you can wrap it in Array(), like this:
file_type = Array(#files).first.type
if file_type == :something
elsif file_type == :something_else
end
What Array() does is it tries to convert the argument passed to it in to an array. If you pass it a single object, it will return an array with that one object in it. If you pass it an array, it does nothing.
>> Array(1) # => [1]
>> Array(Object.new) # => [Object]
>> Array([1,2,3]) # => [1,2,3]

Ruby, limit the number of files returned with Find module per request

I have a controller that calls a find_photos method, passing it a query string (name of file)
class BrandingPhoto < ActiveRecord::Base
def self.find_photos(query)
require "find"
found_photos = []
Find.find("u_photos/photo_browse/photos/") do |img_path|
# break off just the filename from full path
img = img_path.split('/').last
if query.blank? || query.empty?
# if query is blank, they submitted the form with browse all- return all photos
found_photos << img
else
# otherwise see if the file includes their query and return it
found_photos << img if img.include?(query)
end
end
found_photos.empty? ? "no results found" : found_photos
end
end
This is just searching a directory full of photos- there is no table backing this.
Ideally what I would like is to be able to limit the number of results returned by find_photos to around 10-15, then fetch the next 10-15 results as needed.
I was thinking that the code to do this might involve looping through 10 times and grabbing those files- store the last filename in a variable or as a parameter, and then send that variable back to the method, telling it to continue the search from that filename.
This assumes that the files are looped through in the same order everytime, and that there is no simpler way to accomplish this.
If there are any suggestions, I'd love to hear them/see some examples of how you'd accomplish this.
Thank you.
The first thing that comes to mind for this problem is to cut the array down after you come out of the loop. This wouldn't work well with a ton of files though A different solution might be to add a break for the size of the array viz. break if found_photos.length > 10 inside the loop
It's not too hard to do what you want, but you need to consider how you'll handle entries that are added or removed in-between page loads, filenames with UTF-8 or Unicode characters, and embedded/parent directories.
This is old-school code for the basis for what you're talking about:
require 'erb'
require 'sinatra'
get '/list_photos' do
dir = params[ :dir ]
offset = params[ :offset ].to_i
num = params[ :num ].to_i
files = Dir.entries(dir).reject{ |fn| fn[/^\./] || File.directory?(File.join(dir, fn)) }
total_files = files.size
prev_a = next_a = ''
if (offset > 0)
prev_a = "<a href='/list_photos?dir=#{ dir }&num=#{ num }&offset=#{ [ 0, offset - num ].max }'><< Previous</a>"
end
if (offset < total_files)
next_a = "<a href='/list_photos?dir=#{ dir }&num=#{ num }&offset=#{ [ total_files, offset + num ].min }'>Next >></a>"
end
files_to_display = files[offset, num]
template = ERB.new <<EOF
<html>
<head></head>
<body>
<table>
<% files_to_display.each do |f| %>
<tr><td><%= f %></td></tr>
<% end %>
</table>
<%= prev_a %> | <%= total_files %> files | <%= next_a %>
</body>
</html>
EOF
content_type 'text/html'
template.result(binding)
end
It's a little Sinatra server, so save it as test.rb and run from the command-line using:
ruby test.rb
In a browser connect to the running Sinatra server using a URL like:
http://hostname:4567/list_photos?dir=/path/to/image/files&num=10&offset=0
I'm using Sinatra for convenience, but the guts of the routine is the basis for what you want. How to convert it into Rails terms is left as an exercise for the reader.

group_by education - rails 3

I am building a prototype of a education application using Rails 3, omniauth and the facebook graph api. So when a User log in to my application he uses his facebook account, I grab all his education history and his friends education_history.
I would like to group every User friends education likes this:
I have tried something like this:
<ul class="friends-list">
<%= current_user.friends.group_by(&:highschool_name) do |highschool_name|
p "<li>#{highschool_name}</li>"
end
%>
</ul>
And I get a syntax error.
The User tabel look like this:
[id, name, image, location, highschool_name, highschool_year, college_name, college_year, graduteschool_name, graduate_year ]
And the Friend tabel looks like this:
[id, uid, name, image, higschool_name, college_name, graduateschool_name, user_id]
How do solve my problem using active record, without loops because their are not effectivity.. right?
You can't use p or puts in ERB files. Think of ERB files as one big string concatenated together. Like "string 1" + "string 2" + "string 3".
That's all ERB does - it just pastes strings together into one big string. You can't call puts inside this concatenation operation. So everything in the ERB file needs to be a string. The output from a puts call just 'goes up in smoke' since a puts call does not return a string, it writes to stdout instead.
Next we look at group_by: it returns a Hash:
---------------------------------------------------- Enumerable#group_by
enum.group_by {| obj | block } => a_hash
------------------------------------------------------------------------
Returns a hash, which keys are evaluated result from the block,
and values are arrays of elements in enum corresponding to the key.
(1..6).group_by {|i| i%3} #=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]}
So putting everything together we could do something like this:
<% current_user.friends.group_by(&:highschool_name).each do |hsname, friends| %>
<% next if hsname.blank? %>
<li><%= hsname %></li>
<% friends.each do |friend| %>
<%= image_tag(friend.img_url) %> # <- Or wherever you get the img url from
<% end %>
<% end %>

Resources