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

Undefined method _attacher #2

Open
Arvinje opened this issue Dec 8, 2016 · 12 comments
Open

Undefined method _attacher #2

Arvinje opened this issue Dec 8, 2016 · 12 comments

Comments

@Arvinje
Copy link

Arvinje commented Dec 8, 2016

I'm using shrine 2.5.0, reform 2.2.3 and shrine-reform 0.1.4 and I get this exception whenever I try to validate:

undefined local variable or method `campaign_cover_attacher' for #<#<Class:0x007fda5eb59a60>:0x007fda5eca7a70>

I simply added CampaignCoverUploader[:campaign_cover] to both the form and the model and now I'm getting the error when i call validate on the form object. Seems like it's expecting this method to be available on the model, 'cause as soon as I implement an attr_accessor for campaign_cover_attacher, the error changes.

Did I set it up correctly? am I missing something?

@janko
Copy link
Member

janko commented Dec 9, 2016

@Arvinje Can you post me your exact setup? Perferably in a self-contained script which I can run with ruby, something in the lines of:

require "shrine"
require "shrine/storage/file_system"
require "tmpdir"

Shrine.storages = {
  cache: Shrine::Storage::FileSystem.new(Dir.tmpdir),
  store: Shrine::Storage::FileSystem.new(Dir.tmpdir),
}

Shrine.plugin :activerecord
Shrine.plugin :reform

class CampaignCoverUploader < Shrine
end

require "active_record"

ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Base.connection.create_table(:records) { |t| t.text :compaign_cover_data }

class Record < ActiveRecord::Base
  include CampaignCoverUploader[:campaign_cover]
end

require "reform"
require "reform/rails"

class Form < Reform::Form
  include CampaignCoverUploader[:campaign_cover]
end

record = Record.new
form   = Form.new(record)
form.validate(campaign_cover: File.open(__FILE__))
form.save

puts record.campaign_cover

For some reason this script raises an error for me on the form.validate line, I don't get why:

/Users/janko/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/activemodel-5.0.0.1/lib/active_model/naming.rb:150:in `initialize': Class name cannot be blank. You need to supply a name argument when anonymous class given (ArgumentError)
        from /Users/janko/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/reform-2.1.0/lib/reform/form/active_model.rb:79:in `new'
        from /Users/janko/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/reform-2.1.0/lib/reform/form/active_model.rb:79:in `active_model_name_for'
        from /Users/janko/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/reform-2.1.0/lib/reform/form/active_model.rb:73:in `model_name'
        from /Users/janko/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/reform-2.1.0/lib/reform/form/active_model.rb:85:in `model_name'
        from /Users/janko/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/reform-2.1.0/lib/reform/form/active_model/validations.rb:95:in `initialize'
        from /Users/janko/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/reform-2.1.0/lib/reform/form/active_model/validations.rb:55:in `new'
        from /Users/janko/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/reform-2.1.0/lib/reform/form/active_model/validations.rb:55:in `call'
        from /Users/janko/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/reform-2.1.0/lib/reform/validation/groups.rb:57:in `block in call'
        from /Users/janko/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/reform-2.1.0/lib/reform/validation/groups.rb:51:in `each'
        from /Users/janko/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/reform-2.1.0/lib/reform/validation/groups.rb:51:in `call'
        from /Users/janko/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/reform-2.1.0/lib/reform/validation.rb:36:in `valid?'
        from /Users/janko/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/reform-2.1.0/lib/reform/contract/validate.rb:18:in `validate!'
        from /Users/janko/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/reform-2.1.0/lib/reform/contract/validate.rb:10:in `validate'
        from /Users/janko/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/reform-2.1.0/lib/reform/form/validate.rb:23:in `validate'
        from script.rb:35:in `<main>'

@Arvinje
Copy link
Author

Arvinje commented Dec 9, 2016

@janko-m I ran the script you purposed. (The exact same one)
If I use ActiveModel for validation, I get the same error as yours. However, since I use dry-validation ( which needs to be specified via Rails.application.config.reform.validations = :dry ), I get an undefined local variable or method `campaign_cover_attacher' exception.
BTW, I didn't add any validations to the form.

@coatezy
Copy link

coatezy commented Feb 7, 2017

Hey,

I'm also experiencing the same issue when using Dry validations. The issue is that the attacher instance variable is not available within the validate block's scope when using Dry validations.

If I replace

validate do
  #{@name}_attacher.errors.each do |message|
    errors.add :#{@name}, message
  end
end

with

def validate(params)
  result = super(params)

  #{@name}_attacher.errors.each do |message|
    errors.add :#{@name}, message
  end

  result
end

It has access to the attacher and can add any errors.

Hope this helps you identify and resolve the issue.

@coatezy
Copy link

coatezy commented Feb 7, 2017

P.S seems to be working fine when using Active Model validations.

@janko
Copy link
Member

janko commented Feb 8, 2017

@coatezy Thanks for the info, I will definitely look into this soon. Being able to use shrine-reform with dry-validation is definitely more important to me than ActiveModel (even though I'm testing only with ActiveModel), so I want to get to the bottom of this.

@coatezy
Copy link

coatezy commented Feb 8, 2017

@janko-m Good to hear. If I get 5 minutes I will ask over on the Trailblazer Gitter room to see if anyone can suggest where is best to check/assign any errors in a way that works for both ActiveModel and Dry validations.

@coatezy
Copy link

coatezy commented Jun 26, 2017

@janko-m Not sure if you ever had a chance to look in to this?

I am now using shrine-reform with Dry-V. My previous work around worked okay until I had multiple uploaders within a single form. Because I was calling super within a class_eval only the final validator worked.

I am now using prepend and all validators work as expected. 😄

Replaced:

validate do
  #{@name}_attacher.errors.each do |message|
    errors.add :#{@name}, message
  end
end

With:

prepend(::Module.new do
  def validate(params)
    super(params)

    #{@name}_attacher.errors.each do |message|
      errors.add :#{@name}, message
    end

    errors.empty?
  end
end)

@janko
Copy link
Member

janko commented Jun 27, 2017

I haven't had a chance too look at this, thank you for the update!

I you have time, I would definitely appreciate a pull request for this 😉

@coatezy
Copy link

coatezy commented Jul 25, 2017

Sorry @janko-m - Only just returned to the project that required TRB/Shrine file uploads. The approach above worked fine until I wanted to check for the presence of the upload using DRY-V. With a presence validation on image Dry responds with a not present validation error.


module Blog::Contract
  class Create < Reform::Form
    include Dry
    include ::ImageUploader::Attachment.new(:image)

    property :title
    property :body

    validation do
      required(:title).filled
      required(:body).filled
      required(:image).filled
    end
  end
end

There must some kind of ordering issue as if I move

(properties & instance_methods).each do |name|
  send(:property, name, virtual: true)
end

above form.class_eval the image data is passed through to Dry-V and validation is successful but all the expected instance variables such as image_data etc is not populated so it then falls over when syncing the data to the model and saving.

Happy to continue playing if you have any suggestions on where I can look next. 😉

@janko
Copy link
Member

janko commented Jul 25, 2017

@coatezy Ah, I'm guessing Reform internals changed a bit since I wrote shrine-reform. I think Reform::Form.property internally calls Reform::Form.create_accessors, that's why they're defined in that order. But I remember that I had a lot of struggles to make it work then, so I don't know what changed now.

The main problem was defining properties corresponding to the possible Shrine attributes, so that it passes Reform's mass assignment, but without defining accessors for those attributes (as it should use Shrine's accessors), and without attempting to sync them, because any assignment through those attributes write data to the image_data attribute, so none of these other attributes (specified on top of the file) should be synchronized by Reform.

Those were the main challenges, it would be great if you could find time to look into it a bit deeper. I cannot find time lately, latest updates to tus-ruby-server took a significant portion of my energy 😛

@janko
Copy link
Member

janko commented Jul 26, 2017

Let's wait until Reform 2.3.0 is released, and go from there (it's currently in RC phase).

@coatezy
Copy link

coatezy commented Aug 3, 2017

Had a chat with Nick and when using Trailblazer he believes that the uploader should not be part of the form/contract. I have now written a step to handle uploading within the operation.

  def upload_attachment!(options, model:, **)
    attacher = ::FileUploader::Attacher.new(model, :attachment)
    contract = options['contract.default']

    attacher.assign(contract.attachment)

    if attacher.errors.any?
      attacher.errors.each do |error|
        contract.errors.add(:attachment, error)
      end

      return false
    else
      attacher.promote
    end
  end

I do often use Reform on it's own though so would be great to see this plugin work Reform and Dry-V in the future. 😄

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

No branches or pull requests

3 participants