Rails 3 Cache - Errno::ENOENT: No such file or directory - ruby-on-rails-3

Error:
Errno::ENOENT: No such file or directory - .../production/releases/20120224120523/tmp/cache/55B/D80/views%2Ffooter
View:
<% cache("footer") do %>
<%= render :partial => "partials/footer" %>
<% end %>
Cache sweeper:
def after_create()
expire_fragment("footer")
end
What could be wrong? My cache folder has chmod 744, and the file is actually there when I look.
Edit:
Here is the backtrace: http://pastie.org/4103699

Related

Encoding::UndefinedConversionError when trying to upload an image

I am using the following code to upload the image in /public/uploads/ folder in my root rails directory.
uploaded_io = params[:product_image]
File.open(Rails.root.join('public','uploads', uploaded_io.original_filename), 'w') do |file|
file.write(uploaded_io.read)
end
My form looks like this
<%= form_tag({:action => :configure_product}, :multipart => true) do %>
<%= label_tag(:product_image, "Image:") %><br />
<%= file_field_tag 'product_image' %>
<%= submit_tag "Save and add another", :name => 'save and add another' %>
<%= submit_tag "Save", :name => 'save' %>
<% end %>
but when trying to submit the form I get the following error.
Encoding::UndefinedConversionError in ConfigureCategoryController#configure_product
"\xFF" from ASCII-8BIT to UTF-8
I replaced the writing mode from 'w' to 'wb' and now I am getting
NoMethodError in ConfigureCategoryController#configure_product
undefined method `name' for nil:NilClass
New at rails. Would surely appreciate the help.
You'll need to open the file as a binary file by appending b to the open type.
File.open("#{ Rails.root }/tmp/uploaded_image.gif", "wb") do |f|
The other issue you're having is specific to whatever it is your application does.

Rails file uploading and Heroku

I have a problem with file uploading on Heroku server.
(Also a hint about the right way of doing such type of things with rails would be greatly appreciated - I'm very new in RoR).
All this code is about uploading some CSV file, then allowing user to tweak couple of settings, and parse file after all. This usually work on localhost (several times I get troubles with value stored in session), but on Heroku it is always die on upload.
In one of the neighborhood questions was written that Heroku store file only during singe instance run, but I still couldn't find anything about this in Heroku's docs. Should I store file data in the db right after upload, so in such case it always be available? The downside - files could be pretty big, about 10-20Mb, it isn't looks nice.
Heroku logs say:
2012-05-21T19:27:20+00:00 app[web.1]: Started POST "/products/upload" for 46.119
.175.140 at 2012-05-21 19:27:20 +0000
2012-05-21T19:27:20+00:00 app[web.1]: Processing by ProductsController#upload
as HTML
2012-05-21T19:27:20+00:00 app[web.1]: Parameters: {"utf8"=>"тЬУ", "authenticit
y_token"=>"aqJFg3aqENfxS2lKCE4o4txxkZTJgPx36SZ7r3nyZBw=", "upload"=>{"my_file"=>
#<ActionDispatch::Http::UploadedFile:0x000000053af020 #original_filename="marina
-AutoPalmaPriceList_2011-07-30.txt", #content_type="text/plain", #headers="Conte
nt-Disposition: form-data; name=\"upload[my_file]\"; filename=\"marina-AutoPalma
PriceList_2011-07-30.txt\"\r\nContent-Type: text/plain\r\n", #tempfile=#<File:/t
mp/RackMultipart20120521-1-10g8xmx>>}, "commit"=>"Upload"}
2012-05-21T19:27:20+00:00 app[web.1]:
2012-05-21T19:27:20+00:00 app[web.1]: LoadError (no such file to load -- CSV):
2012-05-21T19:27:20+00:00 app[web.1]: app/controllers/products_controller.rb:8
2:in `upload'
2012-05-21T19:27:20+00:00 app[web.1]:
2012-05-21T19:27:20+00:00 app[web.1]:
2012-05-21T19:27:20+00:00 app[web.1]: cache: [POST /products/upload] invalidate,
pass
The code itself:
ProductsController:
def import
respond_to do |format|
format.html
end
end
def import_adjust
case params[:commit]
when "Adjust"
#col_default = params[:col_data]
#abort #col_default.to_yaml
#update csv reader with form data, restore filters from params
when "Complete"
#all ok, read the whole file
#abort params.to_yaml
redirect_to import_complete
else
#col_default = nil
end
#read first part of the file
#tmp = session[:import_file]
#csv = []
source = CSV.open #tmp, {col_sep: ";"}
5.times do
line = source.readline
if line.size>0
#line_size = line.size
#csv.push line
end
end
#generate a selection array
#selection = select_tag 'col_data[]', options_for_select([['name','name'], ['brand','brand'], ['delivery_time','delivery_time'], ['price','price']])
##csv = [selection * line_size] + #csv
end
def import_complete
#remove all items
#todo check products with line items will not be destroyed.
Product.destroy_all
#abort params.to_yaml
map = {}
cnt = 0
#todo check for params count.
params[:col_data].each do |val|
map[cnt] = val if val != 'ignore'
cnt += 1
end
source = CSV.open session[:import_file], {col_sep: ';'}
source.each do |row|
cnt += 1
if row.size > 0
item = Product.new
map.each do |col, attr|
item[attr] = row[col]
end
item[:provider_id] = params[:adjust][:provider]
item.save
#abort item.to_yaml
end
end
#abort map.to_yaml
#todo response needed.
end
def upload
require 'CSV' #looks like I dont need this in fact.
#tmp = params[:upload][:my_file].path #tempfile
#csv = []
#source = CSV.open #tmp, {col_sep: ";"}
session[:import_file] = params[:upload][:my_file].path
respond_to do |format|
format.html { redirect_to action: 'import_adjust' }
end
end
upload.html.erb:
<h1>Uploaded</h1>
<%= #tmp %>
<% #csv.each do |val| %>
<%= val %>
<% end %>
_form_import.html.erb:
<%= form_for :upload, :html => {:multipart => true}, :url => {action: "upload"} do |f| %>
<%= f.file_field :my_file %>
<%= f.submit "Upload" %>
<% end %>
import_adjust.html.erb:
<h1>New product</h1>
<%= form_for :adjust, :url => {action: "import_adjust"} do |f| %>
<% if #csv %>
<table>
<tr>
<% #line_size.times do |cnt| %>
<td>
<%= select_tag 'col_data[]',
options_for_select([
['--ignore--', 'ignore'],
['name','name'],
['brand','brand'],
['delivery_time','delivery_time'],
['price','price']
], #col_default!=nil ? #col_default[cnt] : nil) %>
</td>
<% end %>
</tr>
<% #csv.each do |val| %>
<tr>
<% val.each do |cell| %>
<td>
<%= cell %>
</td>
<% end %>
</tr>
<% end %>
</table>
<% end %>
<%= f.label :delimiter, 'Разделитель' %>
<%= f.text_field :delimiter %>
<br>
<%= f.label :provider, 'Поставщик' %>
<%#todo default empty option needed! Human mistakes warning! %>
<%= f.select :provider, Provider.all.collect { |item| [item.name, item.id] } %>
<br>
<%= f.label :delimiter, 'Разделитель' %>
<%= f.text_field :delimiter %>
<br>
<%# Adjust for proceed adjusting or Complete for parsing %>
<%= f.submit "Adjust" %>
<%= f.submit "Complete" %>
<% end %>
<%= link_to 'Back', products_path %>
Could you paste the entire controller code? The problem is on line #82, but I can't be 100% confident what line that is if you've stripped the class def and before_filters out.
That said, it looks like the problem is with one of the CSV.open lines. The way you're trying to set session[:import_file] is not guaranteed to work. If you ever run the app on more than one dyno you could have the first request served by your web.1 dyno and the second served by web.2, and they have different file systems and would not be able to see the same temp files.
I'd suggest one of the following:
Do all the processing immediately on the upload and avoid the re-direct.
An improvement on that would be to have the upload store the data somewhere shared and accessible (the database or S3) and have start a background job/process to do the processing.
Best of all would be to upload directly to S3 (I believe the S3 Uploader library can do this, there are probably others) and issue a callback to create a background job to process.
That last option means your web dynos are never tied up handling massive uploads and you don't burden the user with waiting for the latency involved in upload to server->store in S3->schedule background job, it is reduced simply to store in S3 from their perspective.
I have an identical scenario as Lifecoder where a user uploads a file, names the columns using a map_fields plugin (by Andrew Timberlake), and then the file is parsed and processed. Here's how I handle it:
file_field = params[options[:file_field]]
map_fields_file_name = "map_fields_#{Time.now.to_i}_#{$$}"
bucket = S3.buckets[CSV_COUPON_BUCKET_NAME] # gets an existing bucket
obj = bucket.objects[map_fields_file_name]
obj.write( file_field.read )
# Save the name and bucket to retrieve on second pass
session[:map_fields][:bucket_name] = map_fields_file_name
Then on the second pass to process the file, I open the file and read it back into temp for the dyno to process:
# Get CSV data out of bucket and stick it back into temp, so we pick up where
# we left off as far as map_fields is concerned.
bucket = S3.buckets[CSV_COUPON_BUCKET_NAME]
obj = bucket.objects[session[:map_fields][:bucket_name]]
temp_path = File.join(Dir::tmpdir, "map_fields_#{Time.now.to_i}_#{$$}")
File.open(temp_path, 'wb') do |f|
f.write obj.read
end
I had to use the plugin so I could modify the code, as obviously the gem is handled by Heroku and doesn't allow for modifications.

Grab file path from upload

I have an RoR script that when given the file path for an XML file, will parse it. I want to be able to find the file with the GUI, and then allow for my script to run. Here's what I have in the view:
<%= form_for :setup, :html=>{:multipart=>true}, :url=>{action=>"create"} do |f| %>
<%= f.file_filed :my_file %>
<%= f.submit "Upload" %>
<% end %>
The controller for the create area is:
$XML_FILE = params[:my_file]
routers = Router.new
#title = routers.overall_setup
if #title == "Everything worked" then
redirect_to "/"
end
Basically from here, how do you snag the file path out? I know that once the correct file path can be placed to $XML_FILE that the rest of the code works
After you've submited a form you can find upploaded file this way:
path = params[:setup][:my_file][:tempfile].path
where params[:setup][:my_file] is your file_filed name in the form
Rails 3
path = params[:setup][:my_file].path

2 render templates (from devise) on one page (rails 3)

I've installed devise for my rails app, i can go to the sign in page or the sign up page. But I want them both on a welcome page...
So I've made a welcome_page_controller.rb with the following function:
class WelcomePageController < ApplicationController
def index
render :template => '/devise/sessions/new'
render :template => '/devise/registration/new'
end
end
But when i go to the welcome page i get this error:
NameError in Welcome_page#index
Showing /Users/tboeree/Dropbox/rails_projects/rebasev4/app/views/devise/sessions/new.html.erb where line #5 raised:
undefined local variable or method `resource' for #<#<Class:0x104931c>:0x102749c>
Extracted source (around line #5):
2: <% #header_title = "Login" %>
3:
4:
5: <%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>
6: <p><%= f.label :email %><br />
7: <%= f.email_field :email %></p>
8:
Does anybody knows a solution for this problem? Thanks in advance!
Does it have to do with the fact that it is missing the resource function? in the welcome_page controller? It's probably somewhere in the devise controller...?
Regards,
Thijs
Here's how I managed to did it.
I've put a sign up form in my home#index
My files:
view/home/index.html.erb
<%= render :file => 'registrations/new' %>
helper/home_helper.rb
module HomeHelper
def resource_name
:user
end
def resource
#resource = session[:subscription] || User.new
end
def devise_mapping
#devise_mapping ||= Devise.mappings[:user]
end
def devise_error_messages!
return "" if resource.errors.empty?
messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join
sentence = I18n.t("errors.messages.not_saved",
:count => resource.errors.count,
:resource => resource_name)
html = <<-HTML
<div id="error_explanation">
<h2>#{sentence}</h2>
<ul>#{messages}</ul>
</div>
HTML
html.html_safe
end
end
You need that part because Devise works with something called resource and it should be defined so you can call your registration#new anywhere.
Like that, you should be able to register. However, I needed to display errors on the same page. Here's what I added:
layout/home.html.erb (the layout used by index view)
<% flash.each do |name, msg| %>
# New code (allow for flash elements to be arrays)
<% if msg.class == Array %>
<% msg.each do |message| %>
<%= content_tag :div, message, :id => "flash_#{name}" %>
<% end %>
<% else %>
# old code
<%= content_tag :div, msg, :id => "flash_#{name}" %>
<% end %> #don't forget the extra end
<% end %>
I found this code here
And here's something I created: I saved my resource object if invalid in a session so that the user hasn't to fill every field again. I guess a better solution exists but it works and it's enough for me ;)
controller/registration_controller.rb
def create
build_resource
if resource.save
if resource.active_for_authentication?
# We delete the session created by an incomplete subscription if it exists.
if !session[:subscription].nil?
session[:subscription] = nil
end
set_flash_message :notice, :signed_up if is_navigational_format?
sign_in(resource_name, resource)
respond_with resource, :location => redirect_location(resource_name, resource)
else
set_flash_message :notice, :inactive_signed_up, :reason => resource.inactive_message.to_s if is_navigational_format?
expire_session_data_after_sign_in!
respond_with resource, :location => after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords(resource)
# Solution for displaying Devise errors on the homepage found on:
# https://stackoverflow.com/questions/4101641/rails-devise-handling-devise-error-messages
flash[:notice] = flash[:notice].to_a.concat resource.errors.full_messages
# We store the invalid object in session so the user hasn't to fill every fields again.
# The session is deleted if the subscription becomes valid.
session[:subscription] = resource
redirect_to root_path #Set the path you want here
end
end
I think I didn't forget any code. Feel free to use whatever you need.
Also, you can add your sign in form in the same page (something like that:)
<%= form_for("user", :url => user_session_path) do |f| %>
<%= f.text_field :email %>
<%= f.password_field :password %>
<%= f.submit 'Sign in' %>
<%= f.check_box :remember_me %>
<%= f.label :remember_me %>
<%= link_to "Forgot your password?", new_password_path('user') %>
<% end %>
Cheers !

Routing error while using partial form in rails 3

does anyone know how to use a form partial to create and update data about an object? My update method seems to work, but I can't create a new object. Every time I clink on the 'Add new ad' I get this error:[ActionController:Routing Error in Classified#new No route matches {:controller=>classified}]. Here is the code for the partial form: The error points to the first line:
<%= form_for(#classified) do |f| %>
<p>
<%= f.label :title %><br/>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :price %><br/>
<%= f.text_field :price %>
</p>
<p>
<%= f.label :location %><br/>
<%= f.text_field :location %>
</p>
<%= f.label :description %><br/>
<%= f.text_area :description %>
<%= f.label :email %><br/>
<%= f.text_field :email %>
<%= f.submit %>
<% end %>
<%= link_to 'Back', {:action => 'list'} %>
Here are my methods for new, edit and update in the Classified controller class:
def new
#classified=Classified.new
end
Here is the 'def create' method:
def create
#classified = Classified.new(params[:classified])
if #classified.save
redirect_to :action => 'list'
else
render :action => 'new'
end
end
I suspect the problem is in my config/routes.rb. I already have this line:
resources :classified
I have also put:
root :to => "Classified#list"
root :to => "Classified#new"
root :to => "Classified#show"
root :to => "Classified#edit"
root :to => "Classified#form
Could the problem be with the routes.rb file. And how comes it works with the update method and not the new method? Please help. I have tried all possible tricks to no avail. I will be so glad. Thanks in advance
I would like to know the result of your rake routes, because you use the singular for your controller classified.
Could it be classifieds, with the S in all your routes? I'm not that sure because resources: classified I guess came from the scaffold and so it should be good, then you miss a `"' on your last line but this could be a typo.
I would recommend having a plural name for the resource, as that is the norm for most resources:
resources :classifieds
You will also need to change your controller name and class name to classifieds_controller and ClassifiedsController
Also, your named routes should be lowercase (although you should get rid of these routes altogether):
root :to => "classifieds#list"
Get rid of the root routes. The resources line will create all the routes you need. And you are only supposed to have one root route in routes.rb and that should point to your home page controller#action.
If you have an action for form, then you don't need that either.. just mentioning this because you created a route for "Classified#form". Controller actions are not necessary for partials.
Your new and create methods and the form look ok at first glance. Try reworking your routes first and if you are still having problems, run rake routes from the command line and post the output in your question and leave me a comment on this answer and I will see if I can help you figure it out.
Read this first:
http://guides.rubyonrails.org/routing.html