Upload text file without a dedicated model using active storage - ruby-on-rails

I have a Task resource containing many tasks. I want to upload a text file containing multiple tasks and import them into the Task model.
I haven't used active storage (AS) before, so I have been combing through the docs. I get that the standard way of using AS is to have a model of records where each record has a file attached. I my case that would mean that I could create an importer model and the have one record for each import action. I feel that that is the wrong approach - I would much rather have an action on the task controller called import that can handle an uploaded file and the import all entries from the file into the task model.
I am trying to make this work with Direct Uploads I have created a form for this:
<%= form_with(model: #task, action: 'start_upload', local: true) do |form| %>
<%= form.file_field :attachments, multiple: false, direct_upload: true %>
<div class="form-group col-sm-6">
<%= form.submit "Save", :class => "btn btn-primary" %>
</div>
<% end %>
This works in some way; the file is uploaded - I see it in a folder (/Users/mhe/Documents/projects/mags/storage/3c/jf/3cjfvr062yd3y6wx8lly4llpdn9x). But I have no way of getting to the file.
The output to the log is:
Started POST "/rails/active_storage/direct_uploads" for ::1 at 2020-04-15 22:18:04 +0200
Processing by ActiveStorage::DirectUploadsController#create as JSON
Parameters: {"blob"=>{"filename"=>"movielist.txt", "content_type"=>"text/plain", "byte_size"=>23610, "checksum"=>"EEzCXGDVCwhcAzfHLvERaw=="}, "direct_upload"=>{"blob"=>{"filename"=>"movielist.txt", "content_type"=>"text/plain", "byte_size"=>23610, "checksum"=>"EEzCXGDVCwhcAzfHLvERaw=="}}}
(0.1ms) begin transaction
ActiveStorage::Blob Create (0.4ms) INSERT INTO "active_storage_blobs" ("key", "filename", "content_type", "byte_size", "checksum", "created_at") VALUES (?, ?, ?, ?, ?, ?) [["key", "ge8ztddg14tapio9cw0x7lf5lu79"], ["filename", "movielist.txt"], ["content_type", "text/plain"], ["byte_size", 23610], ["checksum", "EEzCXGDVCwhcAzfHLvERaw=="], ["created_at", "2020-04-15 20:18:04.108179"]]
(0.8ms) commit transaction
Disk Storage (0.3ms) Generated URL for file at key: ge8ztddg14tapio9cw0x7lf5lu79 (http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhaMlU0ZW5Sa1pHY3hOSFJoY0dsdk9XTjNNSGczYkdZMWJIVTNPUVk2QmtWVU9oRmpiMjUwWlc1MFgzUjVjR1ZKSWc5MFpYaDBMM0JzWVdsdUJqc0dWRG9UWTI5dWRHVnVkRjlzWlc1bmRHaHBBanBjT2cxamFHVmphM04xYlVraUhVVkZla05ZUjBSV1EzZG9ZMEY2WmtoTWRrVlNZWGM5UFFZN0JsUT0iLCJleHAiOiIyMDIwLTA0LTE1VDIwOjIzOjA0LjExM1oiLCJwdXIiOiJibG9iX3Rva2VuIn19--f5314cff4278fed290a6ac3c1ee54c31542e9984)
Completed 200 OK in 19ms (Views: 0.3ms | ActiveRecord: 1.8ms | Allocations: 12779)
Started PUT "/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhaMlU0ZW5Sa1pHY3hOSFJoY0dsdk9XTjNNSGczYkdZMWJIVTNPUVk2QmtWVU9oRmpiMjUwWlc1MFgzUjVjR1ZKSWc5MFpYaDBMM0JzWVdsdUJqc0dWRG9UWTI5dWRHVnVkRjlzWlc1bmRHaHBBanBjT2cxamFHVmphM04xYlVraUhVVkZla05ZUjBSV1EzZG9ZMEY2WmtoTWRrVlNZWGM5UFFZN0JsUT0iLCJleHAiOiIyMDIwLTA0LTE1VDIwOjIzOjA0LjExM1oiLCJwdXIiOiJibG9iX3Rva2VuIn19--f5314cff4278fed290a6ac3c1ee54c31542e9984" for ::1 at 2020-04-15 22:18:04 +0200
Processing by ActiveStorage::DiskController#update as */*
Parameters: {"encoded_token"=>"eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhaMlU0ZW5Sa1pHY3hOSFJoY0dsdk9XTjNNSGczYkdZMWJIVTNPUVk2QmtWVU9oRmpiMjUwWlc1MFgzUjVjR1ZKSWc5MFpYaDBMM0JzWVdsdUJqc0dWRG9UWTI5dWRHVnVkRjlzWlc1bmRHaHBBanBjT2cxamFHVmphM04xYlVraUhVVkZla05ZUjBSV1EzZG9ZMEY2WmtoTWRrVlNZWGM5UFFZN0JsUT0iLCJleHAiOiIyMDIwLTA0LTE1VDIwOjIzOjA0LjExM1oiLCJwdXIiOiJibG9iX3Rva2VuIn19--f5314cff4278fed290a6ac3c1ee54c31542e9984"}
Disk Storage (4.7ms) Uploaded file to key: ge8ztddg14tapio9cw0x7lf5lu79 (checksum: EEzCXGDVCwhcAzfHLvERaw==)
No template found for ActiveStorage::DiskController#update, rendering head :no_content
Completed 204 No Content in 6ms (ActiveRecord: 0.0ms | Allocations: 5806)
Started POST "/tasks/upload" for ::1 at 2020-04-15 22:18:04 +0200
Processing by TasksController#do_upload as HTML
Parameters: {"authenticity_token"=>"wufWKGXHYX/obGYtKkL8SVSy5uSd/Z2XFLDxvLkDKdGQicsUPjEks9riYloTzorjhX8PgFUIj/BXV4VFi1ihKQ==", "attachments"=>"eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBEZz09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--c47b93b4598d01bf7f9b47caa0660fd39ab9b8df", "commit"=>"Save"}
Completed 500 Internal Server Error in 2ms (ActiveRecord: 0.0ms | Allocations: 1300)
And thus the params I get from the upload form are simply:
{"authenticity_token"=>"wufWKGXHYX/obGYtKkL8SVSy5uSd/Z2XFLDxvLkDKdGQicsUPjEks9riYloTzorjhX8PgFUIj/BXV4VFi1ihKQ==", "attachments"=>"eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBEZz09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--c47b93b4598d01bf7f9b47caa0660fd39ab9b8df", "commit"=>"Save", "controller"=>"tasks", "action"=>"do_upload"}
I read about how I should be able to do something like this:
blob = ActiveStorage::Blob.create_after_upload!(
io: params[:file],
filename: params[:file].original_filename,
content_type: params[:file].content_type
)
render json: { filelink: url_for(blob) }
or
ActiveStorage::Blob.service.path_for(params['key'])
But I don't have file nor key in the params - I see them output to the log, though.
So I'm looking for some guidance on how to achieve the usecase... thanks

Related

ActiveStorage::DiskController#update throws 422 when uploading image through ActiveStorage::DirectUploadsController

I've been banging my head against this wall trying to figure out what's going on and would appreciate the help of someone with more experience.
Here's what's going on,
I'm trying to use the ActiveStorage::DirectUploadsController to upload an image. Here's what my custom controller looks like:
class DirectUploadsController < ActiveStorage::DirectUploadsController
# Should only allow null_session in API context, so request is JSON format
protect_from_forgery with: :null_session, if: proc { |c| c.request.format == 'application/json' }
before_action :authenticate_request
private
def authenticate_request
user = AuthorizeApiRequest.call(request.headers).result
render json: { error: 'Not Authorized' }, status: 401 unless user
end
end
However, when hitting the endpoint with a jpeg, I get the following:
Started POST "/direct_uploads" for ::1 at 2020-04-17 17:42:40 -0400
Processing by DirectUploadsController#create as JSON
Parameters: {"blob"=>{"filename"=>"image_picker_1249334B-5119-4F5E-91FB-99D55063495C-37712-0000F8C231364FA5.jpg", "content_type"=>"image/jpeg", "byte_size"=>1476387, "checksum"=>"33cpsUeaiJpTT+o6MkZlAQ=="}, "direct_upload"=>{"blob"=>{"filename"=>"image_picker_1249334B-5119-4F5E-91FB-99D55063495C-37712-0000F8C231364FA5.jpg", "content_type"=>"image/jpeg", "byte_size"=>1476387, "checksum"=>"33cpsUeaiJpTT+o6MkZlAQ=="}}}
Can't verify CSRF token authenticity.
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
↳ app/commands/authorize_api_request.rb:19:in `user'
(0.1ms) begin transaction
ActiveStorage::Blob Create (1.5ms) INSERT INTO "active_storage_blobs" ("key", "filename", "content_type", "byte_size", "checksum", "created_at") VALUES (?, ?, ?, ?, ?, ?) [["key", "2qcdc5dzs615rkxf5xgptki4l5pe"], ["filename", "image_picker_1249334B-5119-4F5E-91FB-99D55063495C-37712-0000F8C231364FA5.jpg"], ["content_type", "image/jpeg"], ["byte_size", 1476387], ["checksum", "33cpsUeaiJpTT+o6MkZlAQ=="], ["created_at", "2020-04-17 21:42:41.075445"]]
(10.2ms) commit transaction
Disk Storage (4.8ms) Generated URL for file at key: 2qcdc5dzs615rkxf5xgptki4l5pe (http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhNbkZqWkdNMVpIcHpOakUxY210NFpqVjRaM0IwYTJrMGJEVndaUVk2QmtWVU9oRmpiMjUwWlc1MFgzUjVjR1ZKSWc5cGJXRm5aUzlxY0dWbkJqc0dWRG9UWTI5dWRHVnVkRjlzWlc1bmRHaHBBeU9IRmpvTlkyaGxZMnR6ZFcxSkloMHpNMk53YzFWbFlXbEtjRlJVSzI4MlRXdGFiRUZSUFQwR093WlUiLCJleHAiOiIyMDIwLTA0LTE3VDIxOjQ3OjQxLjExMVoiLCJwdXIiOiJibG9iX3Rva2VuIn19--b2c1b25a821e7ef4b150012ad33d28e5bb6752e8)
Completed 200 OK in 439ms (Views: 1.9ms | ActiveRecord: 14.4ms | Allocations: 20173)
Started PUT "/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhNbkZqWkdNMVpIcHpOakUxY210NFpqVjRaM0IwYTJrMGJEVndaUVk2QmtWVU9oRmpiMjUwWlc1MFgzUjVjR1ZKSWc5cGJXRm5aUzlxY0dWbkJqc0dWRG9UWTI5dWRHVnVkRjlzWlc1bmRHaHBBeU9IRmpvTlkyaGxZMnR6ZFcxSkloMHpNMk53YzFWbFlXbEtjRlJVSzI4MlRXdGFiRUZSUFQwR093WlUiLCJleHAiOiIyMDIwLTA0LTE3VDIxOjQ3OjQxLjExMVoiLCJwdXIiOiJibG9iX3Rva2VuIn19--b2c1b25a821e7ef4b150012ad33d28e5bb6752e8" for ::1 at 2020-04-17 17:42:41 -0400
Processing by ActiveStorage::DiskController#update as HTML
Parameters: {"encoded_token"=>"eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhNbkZqWkdNMVpIcHpOakUxY210NFpqVjRaM0IwYTJrMGJEVndaUVk2QmtWVU9oRmpiMjUwWlc1MFgzUjVjR1ZKSWc5cGJXRm5aUzlxY0dWbkJqc0dWRG9UWTI5dWRHVnVkRjlzWlc1bmRHaHBBeU9IRmpvTlkyaGxZMnR6ZFcxSkloMHpNMk53YzFWbFlXbEtjRlJVSzI4MlRXdGFiRUZSUFQwR093WlUiLCJleHAiOiIyMDIwLTA0LTE3VDIxOjQ3OjQxLjExMVoiLCJwdXIiOiJibG9iX3Rva2VuIn19--b2c1b25a821e7ef4b150012ad33d28e5bb6752e8"}
Completed 422 Unprocessable Entity in 1ms (ActiveRecord: 0.0ms | Allocations: 218)
It looks like the first request succeeds, then an internal call is made from within the ActiveStorage gem that fails. I've done some digging, and the only similar issue I could find is here: https://github.com/rails/rails/issues/34058
It seems this check fails, causing the 422: https://github.com/rails/rails/blob/bfea0af4ba7d717d6a065b4370e3ccfd8869dde6/activestorage/app/controllers/active_storage/disk_controller.rb#L22-L26
After debugging, it seems this check is failing: token[:content_length] == request.content_length, because token[:content_length] is correct but request.content_length is 0.
I'm not really sure where to look next, I think I found the source of the request but content_length is set correctly from what I can tell. Any idea what's going on?
I'm making the request from a Flutter frontend using this package: https://pub.dev/packages/active_storage/. I'd love to test the API directly using Postman but I can't seem to find any info on the request format.
In case you still have this issue, I forked the active_storage library, to set a Content-Length header as the file is being streamed to Rails. Fork is available here: https://github.com/leesus/dart-active-storage

Back Button Skipping Page in Ruby on Rails application

I have found many generic posts suggesting this has to do with redirects. I believe this may be due to how I have a form set up.
On the plans.html.erb page I have a form with four submits, each going to the same place with different params:
<%= form_with url: :affiliate_select_plan, class: "mx-auto" do |f| %>
<!-- Paid Plans -->
<% #plans.each_with_index do |plan, i| %>
<%= f.button 'Select Plan', value: plan[:name], type: 'submit' %>
<% end %>
<% end %>
I have the affiliate_select_plan_path setup in my routes.rb:
devise_scope :affiliate do
post 'affiliate/select_plan', :to => 'affiliates/registrations#select_plan'
end
The form successfully hits the select_plan method in the controller, which redirects it to the new_affiliate_registration_path, passing the needed params.
def select_plan
redirect_to new_affiliate_registration_path(plan: plan_params[:button])
end
The new method in the controller is called, directing the user to the sign up page:
# GET /resource/sign_up
def new
#plan = AffiliatePlan.find_by(nickname: params.permit(:plan)[:plan].downcase)
super
end
From this page, if the back button on the browser is selected, it will bring the user back to the page they were at before being at plans.html.erb.
Could this be related to the redirect_to?
EDIT:
Here are the logs:
Started GET "/" for 127.0.0.1 at 2020-02-25 19:06:02 -0500
Processing by Affiliates::RegistrationsController#plans as HTML
Rendering affiliates/registrations/plans.html.erb within layouts/application
Rendered affiliates/registrations/plans.html.erb within layouts/application (5.2ms)
Rendered layouts/_google_analytics.html.erb (0.5ms)
[Webpacker] Everything's up-to-date. Nothing to do
Rendered layouts/_header.html.erb (1.2ms)
Rendered layouts/_footer.html.erb (0.7ms)
Completed 200 OK in 195ms (Views: 194.2ms | ActiveRecord: 0.0ms)
Started POST "/partner/select_plan" for 127.0.0.1 at 2020-02-25 19:06:13 -0500
Processing by Affiliates::RegistrationsController#select_plan as JS
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Ck8HGRryriXleQrUjCSKjTrIRLIw273EdSu4WZnFn3kAL1mMmk7jqR1tZgnPniHsMzHFMl81vPBRuvA0/W4uSw==", "button"=>"Local"}
Unpermitted parameters: :utf8, :authenticity_token
Redirected to http://localhost:3000/partners/sign_up?plan=Local
Completed 200 OK in 1ms (ActiveRecord: 0.0ms)
Started GET "/partners/sign_up?plan=Local" for 127.0.0.1 at 2020-02-25 19:06:13 -0500
Processing by Affiliates::RegistrationsController#new as HTML
Parameters: {"plan"=>"Local"}
AffiliatePlan Load (1.2ms) SELECT "affiliate_plans".* FROM "affiliate_plans" WHERE "affiliate_plans"."nickname" = $1 LIMIT $2 [["nickname", "local"], ["LIMIT", 1]]
↳ app/controllers/affiliates/registrations_controller.rb:11
Rendering affiliates/registrations/new.html.erb within layouts/application
Rendered affiliates/registrations/new.html.erb within layouts/application (4.6ms)
Rendered layouts/_google_analytics.html.erb (1.1ms)
[Webpacker] Everything's up-to-date. Nothing to do
Rendered layouts/_header.html.erb (1.2ms)
Rendered layouts/_footer.html.erb (0.7ms)
Completed 200 OK in 191ms (Views: 187.6ms | ActiveRecord: 1.2ms)
I have a hunch that this might have to do with form resubmission: Forms and the back button tend to be a bit wonky at times.
However, instead of going more in depth with this, let me point you in another direction. I'm doing this because to me, this looks like a classic case of someone trying to find a solution to the wrong problem. I'm saying this because based on the code and log snippets you've provided, you're jumping through hoops to pass a parameter (in your case the name of a plan) via multiple actions – which, if I'm right, is just unnecessary.
Here's what I would do instead:
<% #plans.each do |plan| %>
<%=
link_to 'Select Plan',
new_affiliate_registration_path(plan: plan.downcase),
class: 'some-button-class
%>
<% end %>
This way, you don't have to mess around in your controllers in any way. Also, since there is no POST request, you won't have any issues with form (re)population and such things.

How to submit ajax form in Rails 6 with Webpack? Getting ActionController::InvalidAuthenticityToken error

all!
I am following along with the video on GoRails on how to make a chat application using action cable. In the video, I believe Rails 5 is being used, however, I wanted to try it out with Rails 6.
Everything was going great so far. Installed Bootstrap and jQuery and properly configured my environments.js file. It was awesome. Then I get to the part right before we add action cable, and we make the chatroom form remote: true.
I cannot figure out why my form is trying to still submit as HTML instead of JS. On top of that, I am getting an ActionController::InvalidAuthenticityToken error.
Here's how I have my form set up:
<%= simple_form_for [#chatroom, Message.new], remote: true, html: { id: 'message-input' } do |f| %>
<%= f.input :body, label: false, input_html: { rows: 1, autofocus: true } %>
<% end %>
When I submit, I get this error in my rails server:
Started POST "/chatrooms/1/messages" for ::1 at 2019-10-16 21:02:01 -0500
Processing by MessagesController#create as HTML
Parameters: {"message"=>{"body"=>"test3"}, "chatroom_id"=>"1"}
Can't verify CSRF token authenticity.
Completed 422 Unprocessable Entity in 1ms (ActiveRecord: 0.0ms | Allocations: 968)
ActionController::InvalidAuthenticityToken - ActionController::InvalidAuthenticityToken:
Started POST "/__better_errors/cf3c4e5c6fa2d1b1/variables" for ::1 at 2019-10-16 21:02:01 -0500
Not sure what to do. I've googled and came across this but I'm not sure if it's entirely applicable: Using Rails-UJS in JS modules (Rails 6 with webpacker)
Any help would be greatly appreciated!
So, it turns out I had to use form_with instead of form_for in order to get it to process as JS. I guess form_for is slowing being deprecated?
My form now looks like this:
<%= form_with(model: [#chatroom, Message.new]) do |f| %>
<%= f.text_field :body %>
<% end %>
and the output is what I was expecting with out having to submit the CSRF token with JS or skipping the before action in the controller.
Started POST "/chatrooms/1/messages" for ::1 at 2019-10-18 20:15:14 -0500
Processing by MessagesController#create as JS
Parameters: {"authenticity_token"=>"xPBQ+4LOS5aMa7PQ3HEGXAMX6wIIEfQ0Izy/xUqUtleK4mB18IYxC4mOcIoiS5M+FGm6J/WEYMdbM4IVPojScw==", "message"=>{"body"=>"test 5"}, "chatroom_id"=>"1"}
User Load (0.8ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
Chatroom Load (0.3ms) SELECT "chatrooms".* FROM "chatrooms" WHERE "chatrooms"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
↳ app/controllers/messages_controller.rb:19:in `set_chatroom'
(0.1ms) BEGIN
↳ app/controllers/messages_controller.rb:12:in `create'
Message Create (0.7ms) INSERT INTO "messages" ("chatroom_id", "user_id", "body", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["chatroom_id", 1], ["user_id", 1], ["body", "test 5"], ["created_at", "2019-10-19 01:15:14.619853"], ["updated_at", "2019-10-19 01:15:14.619853"]]
↳ app/controllers/messages_controller.rb:12:in `create'
(5.6ms) COMMIT
↳ app/controllers/messages_controller.rb:12:in `create'
Redirected to http://localhost:3000/chatrooms/1
Completed 200 OK in 17ms (ActiveRecord: 7.6ms | Allocations: 4690)
When requesting POST requests rails does authenticity_token check.
In your request from javascript, you'll need to add a header: 'X-CSRF-Token': csrfToken.
You can get csrfToken with the following JS:
const csrfToken = document.querySelector('[name="csrf-token"]').getAttribute('content');
Another solution is to disable verify_authenticity_token, you can add this to your application_controller.rb to disable it or you can add it to controller specific:
skip_before_action :verify_authenticity_token

Rails - Params Not Being Added to Model?

Please help me figure out what I am doing wrong here! I am using s3_direct_upload to upload a basic image to Amazon S3 and then POST to create a record. I can see in the Network tab (firebug) that it is being POST'd. However, I'm not sure why the params are not being added to the DB.
This is what I am getting back:
Started POST "/choices" for 127.0.0.1 at 2013-10-02 17:36:10 -0700
Processing by ChoicesController#create as */*
Parameters: {"url"=>"https://mybucket.s3.amazonaws.com/uploads%2F1380760569802-bneiuk2ghf4-22e59d1c8959be731bc71e31f0a9d7c6%2Fslide0003_image002.jpg",
"filepath"=>"/uploads%2F1380760569802-bneiuk2ghf4-22e59d1c8959be731bc71e31f0a9d7c6%2Fslide0003_image002.jpg",
"filename"=>"slide0003_image002.jpg",
"filesize"=>"73930",
"filetype"=>"image/jpeg",
"unique_id"=>"bneiuk2ghf4",
"choice"=>{
"image"=>"https://mybucket.s3.amazonaws.com/uploads%2F1380760569802-bneiuk2ghf4-22e59d1c8959be731bc71e31f0a9d7c6%2Fslide0003_image002.jpg"
}
}
(0.3ms) BEGIN
(0.4ms) ROLLBACK
Rendered choices/create.js.erb (0.1ms)
Completed 200 OK in 16ms (Views: 6.2ms | ActiveRecord: 0.6ms)
# app/controllers/choice.rb
def create
#choice = Choice.create(choice_params)
end
def choice_params
params.require(:choice).permit!
end
Then my form (some HTML omitted for brevity):
#app/views/new.html.erb
<%= s3_uploader_form callback_url: choices_url, callback_param: "choice[image]", id: "s3-uploader" do %>
<%= file_field_tag :file, multiple: true %>
<% end %>
Any help would be great!
From the 'ROLLBACK", It looks like you are not saving the record. Perhaps, some validations are not being met. Change
#choice = Choice.create(choice_params)
to
#choice = Choice.create!(choice_params)
So that you can get back information concerning why your record is not being saved.

Dont understand why I'm encountering this TypeError (Can't convert nil into String)

Very simple process I'm trying to implement.
On a home page or landing page I want to capture emails for an email list.
If the email passes validation, it gets saved, Great! Everything works fine when there are no errors.
When there is an error like only inputting an 'a' character as shown in the log below. Or even just an empty string I continually get the same TypeError (can't convert nil to String)
Here is the log:
Started GET "/" for 127.0.0.1 at 2013-06-13 13:48:56 -0400
Connecting to database specified by database.yml
Processing by HighVoltage::PagesController#show as HTML
Parameters: {"id"=>"home"}
Rendered shared/_error_messages.html.erb (0.4ms)
Rendered layouts/_visitor_form.html.erb (7.9ms)
Rendered pages/home.html.erb within layouts/application (13.1ms)
Completed 200 OK in 82ms (Views: 39.6ms | ActiveRecord: 1.8ms)
[2013-06-13 13:48:57] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
Started POST "/visitors" for 127.0.0.1 at 2013-06-13 13:48:59 -0400
Processing by VisitorsController#create as HTML
Parameters: {"utf8"=>"✓",authenticity_token"=>"esTPNzNtkmNPTe7Jh+E2aDHNrgocU5Z8g49Nj0QiOhQ=", "visitor"=>{"email"=>""}, "commit"=>"Add to newsletter list"}
(0.1ms) begin transaction
Visitor Exists (0.2ms) SELECT 1 AS one FROM "visitors" WHERE LOWER("visitors"."email") = LOWER('') LIMIT 1
(0.1ms) rollback transaction
Completed 500 Internal Server Error in 39ms
TypeError (can't convert nil into String):
app/controllers/visitors_controller.rb:12:in `create'
Here is the visitors_controller.rb
def create
#visitor = Visitor.new(params[:visitor])
if #visitor.save
flash[:success] = "Your email has been added!"
redirect_to '/'
else
render '/'
end
end
I've also tried
#visitor = Visitor.new(:visitor => params[:visitor][:email])
and a few other sequences with no success.
How can I get the unsuccessful saves to gracefully show the validation errors and allow the user to resubmit.
Here is the layout:
<%= form_for Visitor.new do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.submit "Add to newsletter list", class: "btn btn-large btn-primary" %>
<% end %>
Maybe the high_voltage gem is screwing me up. I don't have enough experience to know.
UPDATE:
rake routes
visitors POST /visitors(.:format) visitors#create
home /home(.:format) pages#home
root / high_voltage/pages#show {:id=>"home"}
page GET /pages/*id high_voltage/pages#show
The problem is, render '/' does not render index page. You have to specify which action page you want to be rendered. According to your routes, this line should look like this:
render 'pages/home'

Resources