1

after trying to implement a file field that users can upload a screenshot with on a feedback with paperclip I recieved some 'no handle errors'. I also made a question about my paperclip issue here.

By looking at the comments to my question it might have to do with multipart.

BUT since I don't use a rails form I can't do something like form_for multipart true. I'm handling some js via my current form and don't really want to change all of this, that why I now tried switching from deprecated paperclip to rails active storage. So far so good.

Got my form still running and works fine until I come to the point of writing the screenshot in the database.

This is a example response of what I get right now when submitting a feedback.

Started POST "/feedback" for 127.0.0.1 at 2018-10-25 12:21:13 +0200
Processing by FeedbackController#create as */*
  Parameters: {"name"=>"dunnothename", "message"=>"blablablablablabla", "topic"=>"Bug", "screenshot"=>"C:\\fakepath\\dhdr.jpeg"}
  User Load (0.5ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
   (0.2ms)  BEGIN
  Feedback Create (41.3ms)  INSERT INTO "feedbacks" ("message", "topic", "name", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id"  [["message", "blablablablablabla"], ["topic", "Bug"], ["name", "dunnothename"], ["created_at", "2018-10-25 10:21:13.410630"], ["updated_at", "2018-10-25 10:21:13.410630"]]
   (0.6ms)  COMMIT
   (0.2ms)  BEGIN
   (0.2ms)  COMMIT
No template found for FeedbackController#create, rendering head :no_content
Completed 204 No Content in 1268ms (ActiveRecord: 48.1ms)

When trying to add the screenshot param to my controller-method ( @feedback = Feedback.create name: ....., screenshot: params[:screenshot]) Ill get the following response:

Started POST "/feedback" for 127.0.0.1 at 2018-10-25 12:31:34 +0200
Processing by FeedbackController#create as */*
  Parameters: {"name"=>"dunnothename", "message"=>"blablablablablabla", "topic"=>"Bug", "screenshot"=>"C:\\fakepath\\dhdr.jpeg"}
  User Load (0.7ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
Completed 500 Internal Server Error in 64ms (ActiveRecord: 11.0ms)



ActiveSupport::MessageVerifier::InvalidSignature - ActiveSupport::MessageVerifier::InvalidSignature:
  app/controllers/feedback_controller.rb:6:in `create'

Feedback.rb

class Feedback < ApplicationRecord
  validates :name, presence: true, length: {minimum: 3}
  validates :message, presence: true, length: {minimum: 5}
  validates :topic, length: {minimum: 3}

  has_one_attached :screenshot
end

_feedback.html.erb

<div id="feedback-message" class="feedback-message" style="color: green;">Feedback sent</div>
<span class="label label-info">Name</span><%= text_field_tag :name, "", class: 'form-control' %>
<span class="label label-info">Topic</span>
<select name="topic" id="topic" class="form-control">
  <option value="Bug">Bug</option>
  <option value="Suggestion">Suggestion</option>
  <option value="Other">Other</option>
</select>
<span class="label label-info">Screenshot</span>
<label class="image-upload form-control">
  <i class="fa fa-cloud-download" id="upload_button"></i>
  <input id="upload_input" type="file" name="feedback[screenshot]"/>
</label>
<span class="label label-info">Message</span> <%= text_area_tag :message, "", class: 'form-control', rows: 3 %>
<hr>
<%= submit_tag 'Submit', id: 'submit-feedback', class: 'btn btn-success center' %>

<script>
    $(document).ready(function () {
        var msg = document.getElementById('feedback-message');
        var submit = $('#submit-feedback');
        submit.click(function () {
            msg.style.display = 'block';
            submit.prop('disabled', true);
            setTimeout(function () {
                submit.prop('disabled', false);
                msg.style.display = 'none';
            }, 5000);
            $.ajax({
                url: '/feedback',
                type: 'POST',
                data: {
                    authenticity_token: $('[name="authenticity_token"]').val(),
                    name: $('#name').val(),
                    message: $('#message').val(),
                    topic: $('#topic').val(),
                    screenshot: $('#upload_input').val(),
                },
            });
        });
    });
    var button = document.getElementById('upload_button');
    var input = document.getElementById('upload_input');

    var span = document.createElement('span');
    span.style.paddingLeft = '20px';
    span.style.color = 'green';
    button.appendChild(span);

    input.style.display = 'none';
    button.style.display = 'initial';
    button.addEventListener('click', function (e) {
        e.preventDefault();
        input.click();
    });
    input.addEventListener('change', function () {
        span.innerText = '' + this.value;
    });
</script>

feedback_controller.rb

class FeedbackController < ApplicationController
  def index;
  end

  def create
    @feedback = Feedback.create name: params[:name], message: params[:message], topic: params[:topic]
    @feedback.screenshot.attach(params[:screenshot])
    authorize @feedback
    if @feedback.save
      #FeedbackMailer.with(user: @user).feedback_sent.deliver_later
    end
  end
end

Update:

After trying to implement what @Niraj mentioned I get the following response:

Started POST "/feedback" for 127.0.0.1 at 2018-10-25 13:06:34 +0200
Processing by FeedbackController#create as */*
  Parameters: {"name"=>"askdalskjdajsdpojapsdo", "message"=>"asdasldkaspdkasüpdkapsod", "topic"=>"Bug", "screenshot"=>"C:\\fakepath\\dhdr.jpeg"}
  User Load (0.4ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
   (0.2ms)  BEGIN
  Feedback Create (1.4ms)  INSERT INTO "feedbacks" ("message", "topic", "name", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id"  [["message", "asdasldkaspdkasüpdkapsod"], ["topic", "Bug"], ["name", "askdalskjdajsdpojapsdo"], ["created_at", "2018-10-25 11:06:34.518275"], ["updated_at", "2018-10-25 11:06:34.518275"]]
   (0.9ms)  COMMIT
  ActiveStorage::Attachment Load (0.3ms)  SELECT  "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = $1 AND "active_storage_attachments"."record_type" = $2 AND "active_storage_attachments"."name" = $3 LIMIT $4  [["record_id", 3], ["record_type", "Feedback"], ["name", "screenshot"], ["LIMIT", 1]]
Completed 500 Internal Server Error in 67ms (ActiveRecord: 9.4ms)


ActiveSupport::MessageVerifier::InvalidSignature - ActiveSupport::MessageVerifier::InvalidSignature:
  app/controllers/feedback_controller.rb:7:in `create'

Update2:

class FeedbackPolicy < ApplicationPolicy
  def index?
    true
  end

  def create?
    user.present?
  end

  def new?
    user.present?
  end

  def update?
    return true if user.present?
  end

  def destroy?
    return true if user.present?
  end

  private

  def feedback
    record
  end
end
flenning12
  • 41
  • 8
  • You can't attach file as you mentioned. Use this `@feedback.screenshot.attach(params[:screenshot])` in create action. For more https://edgeguides.rubyonrails.org/active_storage_overview.html – Niraj Kaushal Oct 25 '18 at 11:00
  • @NirajKaushal updated my question – flenning12 Oct 25 '18 at 11:09
  • Now your screenshot is being attached but there stiil a problem due to this line `authorize Feedback`. – Niraj Kaushal Oct 25 '18 at 11:25
  • I don't actually think it has anything to do with it. And I don't think my screenshot gets attached either. It inserts all of the params except for the screenshot. ActiveStorage::Attachment Load doesn't seem to do the trick. BTW. I removed authorize Feedback just for testing. Still recieve the 500 Internal Server Error saying ActiveSupport::MessageVerifier... – flenning12 Oct 25 '18 at 11:31
  • All attachment store in separate table and you can't access it like other columns. Read active storage documentation which i have shared in first comment. Can you share me `FeedbackPolicy` ? – Niraj Kaushal Oct 25 '18 at 11:38
  • Added FeedbackPolicy to my question. If you are correct about what you believe how does the MessageVerifier still appear? – flenning12 Oct 25 '18 at 11:42
  • Change `authorize Feedback` to `authorize @feedback`. I hope it will solve your problem. – Niraj Kaushal Oct 25 '18 at 11:59
  • also add form attribute `enctype="multipart/form-data"` to the form. – Niraj Kaushal Oct 25 '18 at 12:06
  • Did that now. Still recieving 'ActiveSupport::MessageVerifier::InvalidSignature - ActiveSupport::MessageVerifier::InvalidSignature: app/controllers/feedback_controller.rb:7:in `create'' but it goes through. However, I can't seem to find a way to display the images. Obviously if someone shows me a bug on a screenshot I need to inspect it and see it to be able to make changes. However, I can't seem to find a way to display them, or even check if theyre atleast in my directory. – flenning12 Oct 25 '18 at 12:08
  • enctype="multipart/form-data" -> am I able to set this without a form_for or similar? I didn't find anything about that before. Where do I add that in my form above? – flenning12 Oct 25 '18 at 12:11
  • wrap all inputs inside `
    `tag and read this to know how to access attachment https://edgeguides.rubyonrails.org/active_storage_overview.html#linking-to-files , if you have not changed default storage setting then you can find all your uploaded fine inside `storage` folder.
    – Niraj Kaushal Oct 25 '18 at 12:17
  • Okay. That what I was thinking. Tried that but still: No files are anywhere. I dont have a storage folder. local: service: Disk root: <%= Rails.root.join("storage") %> is inside my storage.yml. – flenning12 Oct 25 '18 at 12:28
  • Could you share latest code of `feedback_controller.rb`? – Niraj Kaushal Oct 25 '18 at 12:34
  • Replaced the old `feedback_controller.rb` code with the new one. Thanks for helping me out btw! – flenning12 Oct 25 '18 at 12:41

1 Answers1

1

Note: As discussed on comment section


I have modified your _feedback.html.erb to make file upload working. Please try this code and do let me know. Make sure your have re-started your rails server.

<div id="feedback-message" class="feedback-message" style="color: green;">Feedback sent</div>
<form>
    <span class="label label-info">Name</span><%= text_field_tag :name, "", class: 'form-control' %>
    <span class="label label-info">Topic</span>
    <select name="topic" id="topic" class="form-control">
        <option value="Bug">Bug</option>
        <option value="Suggestion">Suggestion</option>
        <option value="Other">Other</option>
    </select>
    <span class="label label-info">Screenshot</span>
    <label class="image-upload form-control">
        <i class="fa fa-cloud-download" id="upload_button"></i>
        <input id="upload_input" type="file" name="feedback[screenshot]"/>
    </label>
    <span class="label label-info">Message</span> <%= text_area_tag :message, "", class: 'form-control', rows: 3 %>
    <hr>
    <%= submit_tag 'Submit', id: 'submit-feedback', class: 'btn btn-success center' %>
</form>
<script>
    $(document).ready(function () {
        var submit = $('#submit-feedback');
        submit.on('click', function(e) {
            e.preventDefault();
            var msg = document.getElementById('feedback-message');
            var formData = new FormData();
            formData.append('authenticity_token', $('[name="authenticity_token"]').val());
            formData.append('name', $('#name').val());
            formData.append('message', $('#message').val());
            formData.append('topic', $('#topic').val());
            // Attach file
            formData.append('screenshot', $('#upload_input')[0].files[0]); 

            $.ajax({
                url: '/feedback',
                type: 'POST',
                data: formData,
                contentType: false,
                processData: false, 
                beforeSend: function() {
                    msg.style.display = 'none';
                    submit.prop('disabled', true); 
                },
                success: function(resp) {
                    submit.prop('disabled', false);
                    msg.fadIn().delay(5000).fadeOut();
                },
                error: function() {
                    alert('Something went wrong.')
                }
            })

        });
    });
    var button = document.getElementById('upload_button');
    var input = document.getElementById('upload_input');

    var span = document.createElement('span');
    span.style.paddingLeft = '20px';
    span.style.color = 'green';
    button.appendChild(span);

    input.style.display = 'none';
    button.style.display = 'initial';
    button.addEventListener('click', function (e) {
        e.preventDefault();
        input.click();
    });
    input.addEventListener('change', function () {
        span.innerText = '' + this.value;
    });
</script>
Niraj Kaushal
  • 1,452
  • 2
  • 13
  • 20
  • Ayyyy. Finally! It's working. No MessageVerifier anymore, instead some COMMITS and stuff. Got the storage directory in my root as well. Only thing that I don't know how to do yet is showing/linking these. Btw. Is it correct that no image is saved in the storage dir, but a text file is? I guess it's a key? – flenning12 Oct 25 '18 at 13:33
  • Cool!! You can find your images inside `storage` folder. To fetch screenshot of any particular feedback then you can use `url_for(@feedback.screenshot)` or you can check either screenshot is attached or not by calling `@feedback.screenshot.attached?` learn more here https://edgeguides.rubyonrails.org/active_storage_overview.html#linking-to-files – Niraj Kaushal Oct 25 '18 at 13:53
  • Managed to solve everything! Ive had some trouble with variant sizing the records but thats fine. I'll solve this one by my own. Glad you helped me out!! – flenning12 Oct 26 '18 at 06:35