Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should not mutate options[:file_name] #55

Merged
merged 6 commits into from
May 22, 2017
Merged

Should not mutate options[:file_name] #55

merged 6 commits into from
May 22, 2017

Conversation

dustMason
Copy link
Contributor

@dustMason dustMason commented May 12, 2017

The combination of Proc#curry and the is_a?(Proc) conditional create a bug that causes the file name to be set once (the first time a file upload is handled by the Rails process) and then never updated again.

Proc#curry's docs say:

If a sufficient number of arguments are supplied, it passes the supplied arguments to the original proc and returns the result.

In other words, curry does not always return a Proc. Because the Proc's arity is enforced as 1, this means that it will get set to a String after the first run.

This also causes the curious bug of always firing the file_name deprecation warning on all but the first request handled by this code.

A better solution is to simply call the proc on demand.

The combination of Proc#curry and the `is_a?(Proc)` conditional create a bug that causes the file name to be set once (the first time a file upload is handled by the Rails process) and then never updated again.

Proc#curry's docs state:

> If a sufficient number of arguments are supplied, it passes the supplied arguments to the original proc and returns the result.

Because the Proc's arity is enforced as 1, this means that it will get set to a String after the first run.

This also causes the curious bug of always firing the `file_name` deprecation warning on all but the first request handled by this code.

A better solution is to simply call the proc on demand.
@y9v
Copy link
Owner

y9v commented May 15, 2017

@dustMason thank you for your PR.

This is a breaking change, and it has to go to 2.5.0 (there's even an open issue for that)

#50

What I don't understand is the expected behaviour. You write that the file name of the upload does not change after being set once. Do you expect the file to be renamed?

Also regarding a weird bug with deprecation warning on the first call: can you please give me more info on that?

@dustMason
Copy link
Contributor Author

dustMason commented May 15, 2017

@lebedev-yury I think I did a poor job explaining the issue. It was a challenge to track down – I'll take another try at describing it.

Looking at your code and the example in the readme, I think the expected behavior is to have the file_name Proc run every time the #{attribute}= method is called.

In other words, given a model class:

class Item < ApplicationRecord
  mount_base64_uploader :file, ItemFileUploader, file_name: -> (item) { item.safe_name }

  def safe_name
    name.parameterize
  end
end

and two instances of that class:

one = Item.new name: "item one"
two = Item.new name: "item two"

I would expect the file uploads of each to have different file names. However the bug makes it so they each have the same name:

one.file = "#{base_64_encoded_file}"
one.save
puts one.file.file.filename # => "item-one.ext"
two.file = "#{base_64_encoded_file}"
two.save
puts two.file.file.filename # => "item-one.ext"

The reason this happens is that the body of the #{attribute}= method mutates the file_name option, setting it to a String. I think you intended to set it to a Proc, but as mentioned before, curry returns a String in this case.

curry only returns another Proc if there are still more arguments left on the given Proc. Since you make sure the given Proc has an arity of 1, this code will never return a Proc.

This is what causes the deprecation warning issue as well. The first call does not produce the warning, because the Proc has not yet been curried. The second and further calls do produce the warning, because the file_name option has been set to a String.

I hope this makes sense!

EDIT: Looking again, I see that I did not fix the problem of mutating options[:file_name] 🤦‍♂️. I will make another commit.

I see now that this change prevents String file_name values from working, so it needs an additional fix for that. Once we agree on the fix I can create another commit. I did not intend this to be a breaking change. EDIT: My latest commit restores the ability to give a String for options[:file_name].

A further fix for the file_name as Proc feature. This _actually_ prevents the mutation of `options[:file_name]` as originally intended, and does not remove the support for setting `options[:file_name]` to a String.
@dustMason
Copy link
Contributor Author

@lebedev-yury let me know if there's anything more I can do to resolve this

@y9v
Copy link
Owner

y9v commented May 19, 2017

Well, the build is failing, rubocop is complaining.

On top of that a test case replicating the issue is missing.

Maybe you need some help with that?

dustMason added 4 commits May 19, 2017 11:21
this also documents the previous mistaken usage of #curry, and why it was triggering the deprecation warning unexpectedly
@dustMason
Copy link
Contributor Author

dustMason commented May 19, 2017

Done.

I tried to add a spec initially, but gave up when I ran into the gem dependency conflict. Turns out it was an easy fix.

I've added the spec describing the issue although at this point it's just a regression test against what ended up being an obscure bug. Up to you on whether or not you want to keep in the test suite. It does, at least, show the failure when run against the previous version of adapter.rb.

I also used #curry in a way that illustrates the behavior explained in my other comments. Feel free to change that too if you think it's silly.

Added specs to assert the deprecation warning, too, since that turned out to be somewhat related.

@y9v
Copy link
Owner

y9v commented May 22, 2017

@dustMason great job! I'm merging this and releasing a new tiny version.

Thank you for your contribution!

@y9v y9v merged commit 4007ece into y9v:master May 22, 2017
@y9v
Copy link
Owner

y9v commented May 22, 2017

bb6b141

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants