Ruby on rails File Upload - ruby-on-rails-3

Today i have a little problem containing a File Upload.
First some Infos:
Rubyversion: 1.9.3p194 (2012-04-20 revision 35410) [x86_64-linux]
Railsversion: Rails 3.1.1
Needed Code:
My Form
<%= form_for #label, :html => { :multipart => true } do |f| %>
<% if #label.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#label.errors.count, "error") %> prohibited this label from being saved:</h2>
<ul>
<% #label.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :file %><br />
<%= f.file_field :file %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
My Model:
class Label < ActiveRecord::Base
attr_accessor :file
attr_reader :file
def file=(file)
log = Logger.new(Rails.root.join("log/label.log").to_s)
log.info "file-Action called"
path=file.tempfile.to_path.to_s
filename="labellist.csv"
dest=Rails.root.join("app/assets/csv/").join(filename).to_s
FileUtils.cp(path, dest)
csv=CsvLabelParser.new
log.info "New Parser initialized!"
csv.parse_csv(dest)
log.info "Variables: path: #{path.inspect} <-----> dest: #{dest.inspect}"
end
end
My Parser
class CsvLabelParser
require 'csv'
def initialize
#logger=Logger.new(Rails.root.join("log/parser.log").to_s)
end
def logger
#logger
end
def parse_csv(path)
counter = 0
read_handle = File.open(path, "rb")
content = read_handle.read
self.logger.info "CONTENT: #{content.inspect}"
read_handle.close
content.each_line do |line|
if counter != 0
csv_array=line.split(";")
self.logger.info "CSV-Array No. #{counter}: #{csv_array.inspect}"
label=Label.new
label.labnr=csv_array[10]
label.name=csv_array[0]
label.firm1=csv_array[3]
label.firm2=csv_array[4]
label.postal=csv_array[7]
label.city=csv_array[8]
label.country=csv_array[9]
label.street=csv_array[5]
label.pob=csv_array[6]
label.save
end
counter += 1
end
end
end
Controller-Log
# Logfile created on 2012-06-06 09:49:23 +0200 by logger.rb/31641
Controller-create-method called! => variables: Params: {"utf8"=>"✓", "authenticity_token"=>"L+fpIMqFA9qe9U/LxU+atFONT8e3L5xEUum1321mRng=", "label"=>{"file"=>#<ActionDispatch::Http::UploadedFile:0x00000003df2318 #original_filename="ADRBW076-Q.csv", #content_type="text/csv", #headers="Content-Disposition: form-data; name=\"label[file]\"; filename=\"ADRBW076-Q.csv\"\r\nContent-Type: text/csv\r\n", #tempfile=#<File:/tmp/RackMultipart20120606-2741-1izzofa>>}, "commit"=>"Create Label", "action"=>"create", "controller"=>"labels"}<-----> Label: #<Label id: nil, labnr: nil, name: nil, firm1: nil, firm2: nil, postal: nil, city: nil, country: nil, street: nil, pob: nil, created_at: nil, updated_at: nil>
So! As you can see i want to upload a CSV-file to parse it into my database. A copy of the File should be stored in a folder called CSV for later use. I've done that about 5 times before and it worked well, but this time it seems, that the file-method in the model isn't called.
For now i only want it to work nothing more there will be some changes to catch errors and stuff like that in the future ;).
I've logged the Controller action, which is called every time. May the Logfile can Help you! For me it looks okay, comparing it to other logfiles.
I've searched for a solution, but everything looks okay to me (maybe i've just forgotten a : or a ,), so i can't really say what's wrong!
Thanks for your help

I have the Solution!
I am using Rails 3.1.1 with Ruby 1.9.3 and it's gemset. The Problem was the new feature "attr_accessible". Normally not used in Rails 3.1.1 it became necessary to make the :file-Field accessible due to the newer gemset. So the Solution is simple, I just had to add:
attr_accessible :file, ect
To the Top of my model and everything worked fine!

Related

railscast #250 Authentication / password cannot be NULL

im getting this error message when i submit signup form:
(im following railscast #250 http://railscasts.com/episodes/250-authentication-from-scratch)
Mysql2::Error: Column 'password' cannot be null:
INSERT INTO `users` (`activated`, `activation_key`, ... , `email`, `password`, `password_salt`, `telephone`, `updated_at`)
VALUES (0, '9cli91cjwmt1rcahaiyefh05xhwy5hvz', ..., 'name#domain.tld', NULL, '$2a$10$4vc0HksIm17rzKDxcYVQiO', 123456789, '2013-06-27 19:16:54')
**Parameters**
{"utf8"=>"✓",
"authenticity_token"=>"DNEv4SuXt5btf+MTqM1xA6BWeT7JUa3OAf4AITFCe18=",
"user"=>{"email"=>"name#domain.tld",
"password"=>"[FILTERED]",
"password_confirmation"=>"[FILTERED]",
"telephone"=>"123456789",
"activation_key"=>"9cli91cjwmt1rcahaiyefh05xhwy5hvz"},
"commit"=>"Create User"}
Form
<%= form_for #user do |f| %>
<% if #user.errors.any? %>
<div class="error_messages">
<h2>Form is invalid</h2>
<ul>
<% for message in #user.errors.full_messages %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :email %><br />
<%= f.text_field :email %>
</p>
<p>
<%= f.label :password %><br />
<%= f.password_field :password %>
...**
i have password value FILTERED in parameter because i use f.password_field.. and therefore i have NULL in SQL command.. f.text_field in email works.. what am i missing ?
only different thing from railscast is i have this in UsersController but it should work
def create
params[:user][:activation_key] = Array.new(32){Random.new.rand(36).to_s(36)}.join
#user = User.new(params[:user])
if #user.save
redirect_to root_url, :notice => "Signed up!"
else
render "new"
end
end
Thank you
EDIT:
in Debug #user.inspect
throw this value
#<User id: nil, address_id: nil, company_id: nil, email: "username#domain.tld", password: nil, telephone: 123456789, activation_key: "jolkxv5bd7c2zgq08tkvb7srwe20tfqc", created_at: nil, updated_at: nil, activated: false, password_salt: nil, password_hash: nil>
i had commented
before_save :encrypt_password
now password_hash and password_salt are generated but password column still NULL :(
i tried new app from scratch and it works.. but im not able to solve this ?
I don't know what exactly is going wrong with your application, but the Railscast you are referring to is kinda dated because nowadays you would use has_secure_password. There is a revised episode of that Railscast, but only paying customers can see the revised episodes.
Of course, nothing keeps you from doing authentication without that new method, and I don't think there is any particular disadvantage in doing so, but if you want to check out how has_secure_password works, look at this little tutorial.
ok i got it, this railscast doesnt use password column ! it uses only: email:string, password_hash:string, password_salt:string

Create a select from existing or create new in a form Rails 3

So I'm trying to set a name attribute of organizations and create a new organization or choose from a previously existing organization from the same form.
I've tried to follow Ryan Bates' railscast on the topic here: http://railscasts.com/episodes/57-create-model-through-text-field
I have also tried numerous solutions from stack. However, I can't quite seem to get it to run (that and I have a validation that does not recognize the virtual attribute I'm using)
so my organizations model:
class Organization < ActiveRecord::Base
has_many :materials
has_many :users
has_and_belongs_to_many :causes
has_and_belongs_to_many :schools, :join_table => 'organizations_schools'
####The following line has been edited ####
attr_accessible :name, :unlogged_books_num, :id, :new_organization_name
attr_accessor :new_organization_name
before_validation :create_org_from_name
validates_presence_of :name
def self.assign_school_to_organization(org, school)
orgschool = OrganizationsSchool.create(:organization_id=> org.id, :school_id=> school[0])
end
def create_org_from_name
create_organization(:name=>new_organization_name) unless new_organization_name.blank?
end
end
I have also tried the create_org_from_name as the following:
def create_org_from_name
self.name = new_organization_name
end
And this does not change the name to the organization name before validating or saving the instance.
I have also tried to change the before_save to before_validation, and that has not worked
My controller for organization (I also tried to change this in create)
def create
respond_to do |format|
#organization = Organization.new(params[:organization])
#organization.name = #organization.new_organization_name unless #organization.new_organization_name.blank?
if #organization.save
#school = params[:school]
Organization.assign_school_to_organization(#organization, #school)
format.html { redirect_to #organization, notice: 'Organization was successfully created.' }
format.json { render json: #organization, status: :created, location: #organization }
else
format.html { render action: "new" }
format.json { render json: #organization.errors, status: :unprocessable_entity }
end
end
end
And finally, I have what my form is doing currently:
<%= form_for(#organization) do |f| %>
<% if #organization.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#organization.errors.count, "error") %> prohibited this organization from being saved:</h2>
<ul>
<% #organization.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<% #schools = School.all %>
<% #organizations = Organization.all %>
<div class="field">
<%= f.label 'Organization Name' %><br />
<%= f.collection_select(:name, #organizations, :name, :name, :prompt=>"Existing Organization") %>
Or Create New
<%= f.text_field :new_organization_name %>
</div>
<div class="field">
<%= f.label :unlogged_books_num %><br />
<%= f.number_field :unlogged_books_num %>
</div>
<div class="field">
<%= f.label 'School' %><br />
<% school_id = nil %>
<%= collection_select(:school, school_id, #schools, :id, :name) %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
==================================EDIT============================================
So currently, when I try to make an organization with something only written in the virtual text field, My log tells me the following:
Processing by OrganizationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"igoefz8Rwm/RHrHLTXQnG48ygTGLydZrzP4gEJOPbF0=", "organization"=> {"name"=>"", "new_organization_name"=>"Virtual Organization", "unlogged_books_num"=>""}, "school"=>["1"], "commit"=>"Create Organization"}
Rendered organizations/_form.html.erb (7.1ms)
Rendered organizations/new.html.erb within layouts/application (8.0ms)
Completed 200 OK in 17ms (Views: 12.2ms | ActiveRecord: 1.0ms)
================================EDIT 2============================================
So this is what I get from the rails console if I try to create a new organization running this command: Organization.create(:new_organization_name=>"Virtual Organization", :unlogged_books_num=>"3")
irb(main):001:0> Organization.create(:new_organization_name=>"Virtual Organization", :unlogged_books_num=>"3")
(0.1ms) BEGIN
(0.1ms) ROLLBACK
=> #<Organization id: nil, name: nil, unlogged_books_num: 3, created_at: nil, updated_at: nil>
If the function of create_org_from_name is self.name = new_organization_name, then the result of the same command from the console is blank:
irb(main):002:1> Organization.create(:new_organization_name=>"Virtual Organization", :unlogged_books_num=>"3")
irb(main):003:1>
You need:
before_validation :create_org_from_name
and
def create_org_from_name
self.name = new_organization_name if not new_organization_name.blank?
end
You don't want to do a create in your before_validation method.

No Method Error for "comments", can't find and correct the nil value to make the comment post

I'm relatively new to rails and am trying to pull off my first polymorphic association with comments.
I am running rails 3.2.3
Edit - When I try to post a comment, my log is returning this error:
Started POST "/comments" for 127.0.0.1 at 2012-05-20 13:17:38 -0700
Processing by CommentsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"SOLcF71+WpfNLtpBFpz2qOZVaqcVCHL2AVZWwM2w0C4=", "comment"=>{"text"=>"Test this comment"}, "commit"=>"Create Comment"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 101 LIMIT 1
Completed 500 Internal Server Error in 126ms
NoMethodError (undefined method `Comment' for nil:NilClass):
app/controllers/comments_controller.rb:13:in `create'
I have tried out many different solutions offered on SO and elsewhere, including the answer from Jordan below, due, I'm sure, to my own inexperience, but have been unable to resolve the error.
The trace calls out line 13 in the Comments Controller and I commented after that line below to mark the error:
class CommentsController < ApplicationController
def index
#commentable = find_commentable
#comments = #commentable.comments
end
def new
#post = Post.find(params[:post_id])
end
def create
#commentable = find_commentable
#comment = #commentable.comments.build(params[:comment]) #<<<<LINE 13
if #comment.save
flash[:notice] = "Successfully created comment."
redirect_to :id => nil
else
render :action => 'new'
end
end
private
def find_commentable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
end
Posts Controller:
def show
#post = Post.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render :json => #post }
end
end
Comment template (in post show)
<ul id="comments">
<% if #comments %>
<h2>Comments</h2>
<% #comments.each do |comment| %>
<li><%= comment.text %></li>
<% end %>
<% else %>
<h2>Comment:</h2>
<% end %>
</ul>
<%= simple_form_for [#commentable,Comment.new], :html => { :class => 'form-horizontal', :multipart => true } do |f| %>
<fieldset>
<%= f.input :text %>
Upload Photo <%= f.file_field :photo %>
</fieldset>
<div class="form-actions">
<%= f.submit nil, :class => 'btn btn-primary' %>
</div>
<% end %>
Post show:
<p id="notice"><%= notice %></p>
<div class="row">
<div class="span2 offset1">
<%= image_tag #post.photo.url(:show) %>
</div>
<div class="span5">
<h1><%= #post.title %></h1>
<p><%= #post.index_text.html_safe %></p>
<p><%= #post.show_text.html_safe %></p>
<%= render "comments/comment" %>
<%= render "comments/form" %>
<% if can? :update, #course %>
<%= link_to 'Edit Post', edit_post_path(#post), :class => 'btn btn-mini' %>
<%= link_to 'Delete Post', #post,
confirm: 'Are you sure?',
method: :delete,
:class => 'btn btn-mini' %>
<%= link_to 'New Post', new_post_path, :class => 'btn btn-mini' %>
<% end %>
</div>
<nav class="span2 offset1">
<ul class="well">
<li>Category 1</li>
<li>Category 2</li>
</ul>
</nav>
</div>
<div class="row offset2">
<%= link_to 'Back to Posts', posts_path, :class => 'btn btn-mini' %>
</div>
Routes:
resources :posts, :has_many => :comments
resources :comments
It is probably something obvious that someone with more experience can resolve. Let me know if anything comes to mind. Brian
The problem is that #commentable is nil, which means that CommentsController#find_commentable is returning nil. I think your regular expression is sound, so that means one of two things is happening in find_commentable:
There aren't any keys in params that match your regex.
Your regex is matching but there aren't any records in the resulting table with the id in value.
Debug this as usual by inspecting params and the records in your database to make sure they look like you expect them to look.
The problem is your find_commentable method.
Here are the params passed to your CommentsController#create:
Started POST "/comments" for 127.0.0.1 at 2012-05-20 13:17:38 -0700
Processing by CommentsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"SOLcF71+WpfNLtpBFpz2qOZVaqcVCHL2AVZWwM2w0C4=", "comment"=>{"text"=>"Test this comment"}, "commit"=>"Create Comment"}
Here is your CommentsController#create:
def create
#commentable = find_commentable
#comment = #commentable.comments.build(params[:comment]) #<<<<LINE 13
def find_commentable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
As you can see, find_commentable expects a param like xx_id (for example, comments_id) which it uses to search for an appropriate class (in case of comments_id, it will be Comment), otherwise it returns nil. Refer classify and constantize here.
Your params do not contain any such param. So, you always get a nil object.
Your find_commentable needs some rework. I think in case of nested_fields, it should be an expression like
/(.+)_attributes$/
instead of
/(.+)_id$/.
And you need to have
:accepts_nested_attributes_for :commentable
in your Comment model class.
I tried both of the above answers, but the problem continued.
I ended up consulting with a friend who suggested the following solution, which I like because it's more elegant than my original attempt and easier to read (for later, when I or someone else need to return to the code):
def find_commentable
if params[:post_id]
Post.find(params[:post_id])
#elsif params[:other_id]
# Other.find(params[:other_id])
else
# error out?
end
end
The commented out section will refer to other associations once I get them up and running.

Rails 3 - how to implement changing case of descriptions based on a check_box_tag (not part of model) in before_save callback in external class

I have an rails 3 application where there are multiple registrations (diagnosis, patient, laboratory test, service, client, user, supplier). Initially these will be populated by seeding the database. The requirement is for the description codes to be mixed case (capitalised first word) when either
1. specified by the application (some configuration setting - yet to be determined)
2. specified by data entry user
At present I have a model, view & controller for Diagnosis which contains two fields:
1. code (always to be capitalised)
2. description (First word capitalised based on check_box_tag value)
Presently I am using a before_save callback in the model to implement the conversion, but I cannot get it to only work when the check_box_tag is not selected i.e. its ignoring the check_box_tag.
I have tried changing the check_box_tag to a check_box adding an attr_assessor to the model (but not the sqlite3 db as it is not required to be stored).
This didn't work either.
How do I accomplish this? How do I override the option to use a checkbox from an internal application configuration file which results in either the checkbox being 'unavailable' or not visible if the application configuration specifies not user selectable?
Model (diagnosis.rb)
require 'DescriptionHelper'
class Diagnosis < ActiveRecord::Base
attr_accessible :code, description
string_correct_case = DescriptionHelper.new([:code, :description])
validates :code, :presence => true, :length => { :minimum => 4, :maximum => 4 }
validates :description, :presence => true
before_save string_correct_case
end
Callback in DescriptionHelper.rb
class DescriptionHelper
def initialize(attribute)
#attrs_to_manage = attribute
end
def before_save(record)
#attrs_to_manage.each do |attribute|
record.send("#{attribute}=", capitaliseWords(record.send("#{attribute}")))
end
end
private
def capitaliseWords(value)
value = value.mb_chars.downcase.to_s.gsub(/\b\w/) { |first| first.upcase }
end
end
Controller (diagnoses_controller.rb)
class DiagnosesController < ApplicationController
def new
#diagnosis = Diagnosis.new
end
def create
#diagnosis = Diagnosis.new(params[:diagnosis])
if #diagnosis.save
flash[:notice] = "Diagnosis created with params [#{#diagnosis.attributes.inspect}" #for debugging, once fixed will be just 'Diagnosis created.'
redirect_to #diagnosis
else
flash[:alert] = "Diagnosis not created."
render :action => "new"
end
end
.. other controller actions - edit, show, destroy
end
View (_form.html.erb)
<%= form_for(#daignosis) do |f| %>
<div class="field">
<%= f.label :code %>
<%= f.text_field :code %>
</div>
<div class="field">
<%= f.label :description %>
<%= f.text_field :description %>
</div>
<div class="field">
<%= check_box_tag("diagnosis_desc_dont_convert", 1, false) %><%= f.label "Leave as entered" %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
When this runs currently the check_box_tag is ignored.
When adding in the model an attar_assessor :description_correctcase and changing the view to use f.check_box 'description_correctcase' this is still ignored.
How does one get this to work?
Thanks in advance from a rails aspiring developer.
Finally got a solution to the problem, after reading and re-reading various SO solutions to component parts of my question. I'm not sure its correct in terms of rails, but it works.
If you can offer me a better solution I would certainly learn from this.
Here is my solution.
Model (diagnosis.rb)
require 'DescriptionHelper'
class Diagnosis < ActiveRecord::Base
attr_accessor :do_not_correctcase
attr_accessible :code, :description, :do_not_correctcase
before_save DescriptionHelper.new([:code, :description]), :if =>
lambda { |d| d.do_not_correctcase.to_s == '0' }
validates :code, :presence => true, :length => { :minimum => 4, :maximum => 4 }
validates :description, :presence => true
end
This I referenced from the following SO solution - https://stackoverflow.com/a/6388691/1108010
Controller (diagnoses_controller.rb)
class DiagnosesController < ApplicationController
def new
#diagnosis = Diagnosis.new
end
def create
#diagnosis = Diagnosis.new(params[:diagnosis])
#diagnosis.do_not_correctcase = params[:diagnosis][:do_not_correctcase]
logger.debug "New diagnoses: #{#diagnosis.attributes.inspect}"
logger.debug "Diagnosis should be valid: #{#diagnosis.valid?}"
logger.debug "code has value #{params[:code]}"
if #diagnosis.save
flash[:notice] = "Diagnosis created with params [#{#diagnosis.attributes.inspect}" #for debugging
redirect_to #diagnosis
else
flash[:alert] = "Diagnosis not created."
render :action => "new"
end
end
.. other controller actions - edit, show, destroy
end
I also changed the view to replace the check_box_tag with a check_box.
View (_form.html.erb)
<%= form_for(#daignosis) do |f| %>
<div class="field">
<%= f.label :code %>
<%= f.text_field :code %>
</div>
<div class="field">
<%= f.label :description %>
<%= f.text_field :description %>
</div>
<div class="field">
<%= f.check_box 'do_not_correctcase' %><%= f.label "Leave as entered" %><br />
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
So despite getting this to work I'm not clear on are the following:
When inspecting the attributes with "#{#diagnosis.attributes.inspect}".
I assume that the reason the attr_accessor variable is not included in the New diagnosis output is that it is not part of the database table and therefore Active Reocrd does not instanciate it as part of the new record with #diagnosis.new
Could someone be kind enough to confirm that.
Why does the log have no value for logger.debug "code has value #{params[:code]}"? What causes the params[:code] to be null in the logger output?
Logfile contained the following entry:
Started POST "/diagnoses" for 127.0.0.1 at 2012-03-05 09:36:38 +0000
Processing by DiagnosesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"RW/mzkhavGeaIW0hVLn0ortTnbCDlrX+FfzH4neLLsA=", "diagnosis"=>{"code"=>"tt02", "description"=>"description for tt02", "do_not_correctcase"=>"1"}, "commit"=>"Create Diagnosis"}
New diagnosis: {"code"=>"tt02", "created_at"=>nil, "description"=>"description for tt02", "updated_at"=>nil}
Diagnosis should be valid: true
code has value
I would dearly like to know what is the correct way to do all this, as I feel this is not very DRY or clean.

How to upload an image with other form inputs via ruby on rails?

I was wondering how to implement an image upload using ruby on rails v3?
What I got so far is the image is uploaded to my public/uploads directory but in the database the hashed value from the form is stored.
EX of hashed value:
!ruby/object:ActionDispatch::Http::UploadedFile
content_type: image/jpeg
headers: |
Content-Disposition: form-data; name="farmer[picture]"; filename="picture.JPG"
Content-Type: image/jpeg
original_filename: picture.JPG
tempfile: !ruby/object:File {}
Controller:
def new
#farmer = Farmer.new
end
def create
#farmer = Farmer.new(params[:farmer])
if #farmer.save
uploaded_io = params[:farmer][:picture]
File.open(Rails.root.join('public', 'uploads', uploaded_io.original_filename), 'w') do |file|
file.write(uploaded_io.read)
end
flash[:success] = "#{#farmer.firstName} #{#farmer.lastName} added"
redirect_to #farmer
else
redirect_to new_path
end
end
Model:
empty
View:
<%= form_for(#farmer, :html => { :multipart => true }) do |f| %>
<div class="field">
<%= f.label :picture, "Picture" %>
<%= f.file_field :picture %>
</div>
<div class="actions">
<%= f.submit "Post"%>
</div>
<% end %>
So what I would like help with is how to store uploads/image.JPG into the database not the hashed value?
Try not to invent bicycle , paperclip gem is what you are looking for, you may found also alternatives at: ruby toolbox
Cheers
Carrierwave is the best for your problem. If you are using peperclip, you may try to replace with carrierwave. if you have any problem, let me know