janko / rodauth-rails

Rails integration for Rodauth authentication framework
https://github.com/jeremyevans/rodauth
MIT License
599 stars 40 forks source link

Handling File Uploads During Account Creation #43

Closed conradbeach closed 3 years ago

conradbeach commented 3 years ago

I'm creating a sign up page for a new application. One of the fields I'd like to add is a profile picture. I'm using Active Storage to handle the upload, so I modified the create-account.html.erb template to this:

<%= form_tag rodauth.create_account_path, method: :post, multipart: true do %>

  ...

  <div class="form-group">
    <%= label_tag :profile_picture %>
    <%= file_field_tag :profile_picture, value: params["profile_picture"] %>
  </div>

  <%= render "submit", value: "Create Account" %>
<% end %>

On the back-end, I'm using the after_create_account hook to create a Profile record where I intend to store the image.

    after_create_account do
      Profile.create!(
        ...
        picture: param("profile_picture"),
      )
    end

But instead of getting a file object of some kind as I would expect, param("profile_picture") is a string that looks like this:

"{:filename=>\"profile-latest.jpg\", :type=>\"image/jpeg\", :name=>\"profile_picture\", :tempfile=>#<Tempfile:/var/folders/sc/2vr8_7k56pz3hr0grcmpkxt00000gn/T/RackMultipart20210529-54743-ib4e4r.jpg>, :head=>\"Content-Disposition: form-data; name=\\\"profile_picture\\\"; filename=\\\"profile-latest.jpg\\\"\\r\\nContent-Type: image/jpeg\\r\\n\"}"

The Profile.create! code above doesn't work, obviously, and instead throws an ActiveSupport::MessageVerifier::InvalidSignature exception.

I tried looking through the rodauth-rails code to determine what's happening, but I failed to figure it out. Is what I've described above the expected behavior?

janko commented 3 years ago

If you look at the source code, the #param method calls #to_s on the param value. I suppose that this was done to normalize the type of param values. For fetching unmodified param values, you can use #raw_param instead.

However, in your case Active Storage will probably be expecting an ActionDispatch::Http::UploadedFile instead of a Rack uploaded file hash, so you'll probably need to fetch the param though the ActionDispatch::Request object, which should correctly encode the param:

    after_create_account do
      Profile.create!(
        ...
        picture: rails_request.params[:profile_picture],
      )
    end
conradbeach commented 3 years ago

Thank you for explaining that, Janko. That works. I'll keep those things in mind for the future.

benoror commented 2 years ago

FTR raw_param is what I needed when fetching a JSON param, otherwise would be a escaped String representation which is hard to convert to Hash or jsonb