trailblazer / reform

Form objects decoupled from models.
https://trailblazer.to/2.1/docs/reform.html
MIT License
2.5k stars 184 forks source link

A problem with file uploading (reform + file_validators) #443

Open rapides opened 7 years ago

rapides commented 7 years ago

Complete Description of Issue

I've already started this topic here too because I'm not sure which one gem of those both refers to that problem. Let's consider following example:

  # .../pitches_controller.rb

  def upload_avatar
    pitch = Pitch.find(params[:id])
    form = PitchAvatarForm.new(pitch)
    if form.validate(pitch_avatar_params)
      form.save
      on_pitch_avatar_upload_succeeded(form)
    else
      on_pitch_avatar_upload_fialed(form)
    end
  end
# .../forms/pitch_avatar_form.rb

class PitchAvatarForm < Reform::Form
  model :pitch

  property :image
  property :image_file_name
  property :image_content_type
  property :image_file_size

  validates :image,
            file_content_type: { allow: ['image/jpeg', 'image/jpg', 'image/png'] },
            file_size:  { less_than: 2.megabytes }
end

On each form#save execution it couses following error:

form.save
NoMethodError: undefined method `sub' for nil:NilClass
from /Users/rapide/.rvm/gems/ruby-2.3.0@bttf/gems/paperclip-4.2.2/lib/paperclip/storage/s3.rb:255:in `s3_object'

I fixed this issue by assigning attributes to the pitch before creating the form but it looks like an ugly hack. Any idea how to solve this in better way?

  # .../pitches_controller.rb - temporary solution

  def upload_avatar
    pitch = Pitch.find(params[:id])
    pitch.assign_attributes(pitch_avatar_params)
    form = PitchAvatarForm.new(pitch)
    if form.validate(pitch_avatar_params)
      form.save
      on_pitch_avatar_upload_succeeded(form)
    else
      on_pitch_avatar_upload_fialed(form)
    end
  end

Expected behavior

Executing form#save should save my file properly.

System configuration

Reform version: 2.2.4

Full Backtrace of Exception (if any)

Full backtrace
--------------

 - paperclip (4.2.2) lib/paperclip/storage/s3.rb:255:in `s3_object'
 - paperclip (4.2.2) lib/paperclip/storage/s3.rb:360:in `block in flush_writes'
 - paperclip (4.2.2) lib/paperclip/storage/s3.rb:331:in `flush_writes'
 - paperclip (4.2.2) lib/paperclip/attachment.rb:238:in `save'
 - delayed_paperclip (3.0.1) lib/delayed_paperclip/attachment.rb:67:in `save'
 - paperclip (4.2.2) lib/paperclip/has_attached_file.rb:91:in `block in add_active_record_callbacks'
 - activesupport (4.2.8) lib/active_support/callbacks.rb:446:in `block in make_lambda'
 - activesupport (4.2.8) lib/active_support/callbacks.rb:228:in `block in halting_and_conditional'
 - activesupport (4.2.8) lib/active_support/callbacks.rb:506:in `block in call'
 - activesupport (4.2.8) lib/active_support/callbacks.rb:506:in `call'
 - activesupport (4.2.8) lib/active_support/callbacks.rb:92:in `__run_callbacks__'
 - activesupport (4.2.8) lib/active_support/callbacks.rb:778:in `_run_save_callbacks'
 - activerecord (4.2.8) lib/active_record/callbacks.rb:302:in `create_or_update'
 - activerecord (4.2.8) lib/active_record/persistence.rb:120:in `save'
 - bullet (5.5.1) lib/bullet/active_record42.rb:47:in `save_with_bullet'
 - activerecord (4.2.8) lib/active_record/validations.rb:37:in `save'
 - activerecord (4.2.8) lib/active_record/attribute_methods/dirty.rb:21:in `save'
 - activerecord (4.2.8) lib/active_record/transactions.rb:286:in `block (2 levels) in save'
 - activerecord (4.2.8) lib/active_record/transactions.rb:351:in `block in with_transaction_returning_status'
 - activerecord (4.2.8) lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `block in transaction'
 - activerecord (4.2.8) lib/active_record/connection_adapters/abstract/transaction.rb:184:in `within_new_transaction'
 - activerecord (4.2.8) lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `transaction'
 - activerecord (4.2.8) lib/active_record/transactions.rb:220:in `transaction'
 - activerecord (4.2.8) lib/active_record/transactions.rb:348:in `with_transaction_returning_status'
 - activerecord (4.2.8) lib/active_record/transactions.rb:286:in `block in save'
 - activerecord (4.2.8) lib/active_record/transactions.rb:301:in `rollback_active_record_state!'
 - activerecord (4.2.8) lib/active_record/transactions.rb:285:in `save'
 - disposable (0.4.2) lib/disposable/twin/save.rb:25:in `save_model'
 - disposable (0.4.2) lib/disposable/twin/save.rb:12:in `save!'
 - disposable (0.4.2) lib/disposable/twin/save.rb:8:in `save'
 - app/controllers/pitches_controller.rb:423:in `upload_avatar'
 - actionpack (4.2.8) lib/action_controller/metal/implicit_render.rb:4:in `send_action'
 - actionpack (4.2.8) lib/abstract_controller/base.rb:198:in `process_action'
 - actionpack (4.2.8) lib/action_controller/metal/rendering.rb:10:in `process_action'
 - actionpack (4.2.8) lib/abstract_controller/callbacks.rb:20:in `block in process_action'
 - activesupport (4.2.8) lib/active_support/callbacks.rb:117:in `call'
 - activesupport (4.2.8) lib/active_support/callbacks.rb:555:in `block (2 levels) in compile'
 - activesupport (4.2.8) lib/active_support/callbacks.rb:505:in `call'
 - activesupport (4.2.8) lib/active_support/callbacks.rb:92:in `__run_callbacks__'
 - activesupport (4.2.8) lib/active_support/callbacks.rb:778:in `_run_process_action_callbacks'
 - activesupport (4.2.8) lib/active_support/callbacks.rb:81:in `run_callbacks'
 - actionpack (4.2.8) lib/abstract_controller/callbacks.rb:19:in `process_action'
 - actionpack (4.2.8) lib/action_controller/metal/rescue.rb:29:in `process_action'
 - actionpack (4.2.8) lib/action_controller/metal/instrumentation.rb:32:in `block in process_action'
 - activesupport (4.2.8) lib/active_support/notifications.rb:164:in `block in instrument'
 - activesupport (4.2.8) lib/active_support/notifications/instrumenter.rb:20:in `instrument'
 - activesupport (4.2.8) lib/active_support/notifications.rb:164:in `instrument'
 - actionpack (4.2.8) lib/action_controller/metal/instrumentation.rb:30:in `process_action'
 - actionpack (4.2.8) lib/action_controller/metal/params_wrapper.rb:250:in `process_action'
 - activerecord (4.2.8) lib/active_record/railties/controller_runtime.rb:18:in `process_action'
 - actionpack (4.2.8) lib/abstract_controller/base.rb:137:in `process'
 - actionview (4.2.8) lib/action_view/rendering.rb:30:in `process'
 - rack-mini-profiler (0.10.2) lib/mini_profiler/profiling_methods.rb:102:in `block in profile_method'
 - actionpack (4.2.8) lib/action_controller/metal.rb:196:in `dispatch'
 - actionpack (4.2.8) lib/action_controller/metal/rack_delegation.rb:13:in `dispatch'
 - actionpack (4.2.8) lib/action_controller/metal.rb:237:in `block in action'
 - actionpack (4.2.8) lib/action_dispatch/routing/route_set.rb:74:in `dispatch'
 - actionpack (4.2.8) lib/action_dispatch/routing/route_set.rb:43:in `serve'
 - actionpack (4.2.8) lib/action_dispatch/journey/router.rb:43:in `block in serve'
 - actionpack (4.2.8) lib/action_dispatch/journey/router.rb:30:in `serve'
 - actionpack (4.2.8) lib/action_dispatch/routing/route_set.rb:817:in `call'
 - omniauth (1.4.2) lib/omniauth/strategy.rb:186:in `call!'
 - omniauth (1.4.2) lib/omniauth/strategy.rb:164:in `call'
 - omniauth (1.4.2) lib/omniauth/strategy.rb:186:in `call!'
 - omniauth (1.4.2) lib/omniauth/strategy.rb:164:in `call'
 - omniauth (1.4.2) lib/omniauth/strategy.rb:186:in `call!'
 - omniauth (1.4.2) lib/omniauth/strategy.rb:164:in `call'
 -  () Users/rapide/.rvm/gems/ruby-2.3.0@bttf/bundler/gems/omnicontacts-320b861e9db0/lib/omnicontacts/middleware/base_oauth.rb:42:in `call'
 -  () Users/rapide/.rvm/gems/ruby-2.3.0@bttf/bundler/gems/omnicontacts-320b861e9db0/lib/omnicontacts/middleware/base_oauth.rb:42:in `call'
 -  () Users/rapide/.rvm/gems/ruby-2.3.0@bttf/bundler/gems/omnicontacts-320b861e9db0/lib/omnicontacts/middleware/base_oauth.rb:42:in `call'
 -  () Users/rapide/.rvm/gems/ruby-2.3.0@bttf/bundler/gems/omnicontacts-320b861e9db0/lib/omnicontacts/builder.rb:27:in `call'
 - bullet (5.5.1) lib/bullet/rack.rb:12:in `call'
 - rack-affiliates (0.4.0) lib/rack-affiliates.rb:50:in `call'
 - warden (1.2.7) lib/warden/manager.rb:36:in `block in call'
 - warden (1.2.7) lib/warden/manager.rb:35:in `call'
 - rack (1.6.5) lib/rack/etag.rb:24:in `call'
 - rack (1.6.5) lib/rack/conditionalget.rb:38:in `call'
 - rack (1.6.5) lib/rack/head.rb:13:in `call'
 - remotipart (1.3.1) lib/remotipart/middleware.rb:32:in `call'
 - actionpack (4.2.8) lib/action_dispatch/middleware/params_parser.rb:27:in `call'
 - actionpack (4.2.8) lib/action_dispatch/middleware/flash.rb:260:in `call'
 - rack (1.6.5) lib/rack/session/abstract/id.rb:225:in `context'
 - rack (1.6.5) lib/rack/session/abstract/id.rb:220:in `call'
 - actionpack (4.2.8) lib/action_dispatch/middleware/cookies.rb:560:in `call'
 - activerecord (4.2.8) lib/active_record/query_cache.rb:36:in `call'
 - activerecord (4.2.8) lib/active_record/connection_adapters/abstract/connection_pool.rb:653:in `call'
 - actionpack (4.2.8) lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
 - activesupport (4.2.8) lib/active_support/callbacks.rb:88:in `__run_callbacks__'
 - activesupport (4.2.8) lib/active_support/callbacks.rb:778:in `_run_call_callbacks'
 - activesupport (4.2.8) lib/active_support/callbacks.rb:81:in `run_callbacks'
 - actionpack (4.2.8) lib/action_dispatch/middleware/callbacks.rb:27:in `call'
 - actionpack (4.2.8) lib/action_dispatch/middleware/reloader.rb:73:in `call'
 - actionpack (4.2.8) lib/action_dispatch/middleware/remote_ip.rb:78:in `call'
 - better_errors (2.1.1) lib/better_errors/middleware.rb:84:in `protected_app_call'
 - better_errors (2.1.1) lib/better_errors/middleware.rb:79:in `better_errors_call'
 - better_errors (2.1.1) lib/better_errors/middleware.rb:57:in `call'
 - actionpack (4.2.8) lib/action_dispatch/middleware/debug_exceptions.rb:17:in `call'
 - web-console (2.3.0) lib/web_console/middleware.rb:28:in `block in call'
 - web-console (2.3.0) lib/web_console/middleware.rb:18:in `call'
 - actionpack (4.2.8) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
 - railties (4.2.8) lib/rails/rack/logger.rb:38:in `call_app'
 - railties (4.2.8) lib/rails/rack/logger.rb:20:in `block in call'
 - activesupport (4.2.8) lib/active_support/tagged_logging.rb:68:in `block in tagged'
 - activesupport (4.2.8) lib/active_support/tagged_logging.rb:26:in `tagged'
 - activesupport (4.2.8) lib/active_support/tagged_logging.rb:68:in `tagged'
 - railties (4.2.8) lib/rails/rack/logger.rb:20:in `call'
 - quiet_assets (1.0.2) lib/quiet_assets.rb:18:in `call_with_quiet_assets'
 - request_store (1.3.2) lib/request_store/middleware.rb:9:in `call'
 - actionpack (4.2.8) lib/action_dispatch/middleware/request_id.rb:21:in `call'
 - rack (1.6.5) lib/rack/methodoverride.rb:22:in `call'
 - rack (1.6.5) lib/rack/runtime.rb:18:in `call'
 - rack (1.6.5) lib/rack/lock.rb:17:in `call'
 - actionpack (4.2.8) lib/action_dispatch/middleware/static.rb:120:in `call'
 - rack (1.6.5) lib/rack/sendfile.rb:113:in `call'
 - rack-mini-profiler (0.10.2) lib/mini_profiler/profiler.rb:282:in `call'
 - railties (4.2.8) lib/rails/engine.rb:518:in `call'
 - railties (4.2.8) lib/rails/application.rb:165:in `call'
 - railties (4.2.8) lib/rails/railtie.rb:194:in `method_missing'
 - thin (1.6.4) lib/thin/connection.rb:86:in `block in pre_process'
 - thin (1.6.4) lib/thin/connection.rb:84:in `pre_process'
 - thin (1.6.4) lib/thin/connection.rb:53:in `process'
 - thin (1.6.4) lib/thin/connection.rb:39:in `receive_data'
 - eventmachine (1.2.3) lib/eventmachine.rb:194:in `run'
 - thin (1.6.4) lib/thin/backends/base.rb:73:in `start'
 - thin (1.6.4) lib/thin/server.rb:162:in `start'
 - thin (1.6.4) lib/thin/controllers/controller.rb:87:in `start'
 - thin (1.6.4) lib/thin/runner.rb:200:in `run_command'
 - thin (1.6.4) lib/thin/runner.rb:156:in `run!'
 - thin (1.6.4) bin/thin:6:in `<top (required)>'
 -  () Users/rapide/.rvm/gems/ruby-2.3.0@bttf/bin/thin:23:in `<main>'
 -  () Users/rapide/.rvm/gems/ruby-2.3.0@bttf/bin/ruby_executable_hooks:15:in `<main>'