Rails Carrierwave NoMethodError

Posted

技术标签:

【中文标题】Rails Carrierwave NoMethodError【英文标题】: 【发布时间】:2014-02-12 20:18:08 【问题描述】:

我正在尝试在我的应用中实现 Jcrop 并不断收到以下错误:

NoMethodError in PeopleController#update
undefined method `body' for nil:NilClass

我正在使用 Rails 4.0.2、Ruby 2.0.0p0、Bootstrap 2.3.2、Jcrop 0.9.12、Rmagick 2.13.2

奇怪的是,如果我重新加载此人的页面,裁剪后的图片会保存到 S3 并显示在 UI 中。但是,每次我尝试裁剪图片时都会发生此错误。

这是我的人物模型。我已经用 ** 标记了生成错误时在浏览器中突出显示的行。

class Person < ActiveRecord::Base
    validates_presence_of :fname, :lname, :company, :department, :title, :work_phone, :mobile, :office, :address, :city, :state, :zipcode, :country, :suite, :column

    attr_accessor :crop_x, :crop_y, :crop_w, :crop_h

    mount_uploader :photo, PhotoUploader

    after_update :crop_photo

  def crop_photo
    **photo.recreate_versions! if crop_x.present?**
  end
end

这是我的 PhotoUploader.rb 文件:

# encoding: utf-8

class PhotoUploader < CarrierWave::Uploader::Base

  # Include RMagick or MiniMagick support:
  include CarrierWave::RMagick
  # include CarrierWave::MiniMagick

  # Choose what kind of storage to use for this uploader:
  # storage :file
   storage :fog

   include CarrierWave::MimeTypes
   process :set_content_type

  # Override the directory where uploaded files will be stored.
  # This is a sensible default for uploaders that are meant to be mounted:
  def store_dir
    "uploads/#model.class.to_s.underscore/#mounted_as/#model.id"
  end

  # Provide a default URL as a default if there hasn't been a file uploaded:
  def default_url
    # For Rails 3.1+ asset pipeline compatibility:
    ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))

    # "/images/fallback/" + [version_name, "default.png"].compact.join('_')
  end

  # Process files as they are uploaded:
  # process :scale => [200, 300]
  #
  # def scale(width, height)
  #   # do something
  # end

  # Create different versions of your uploaded files:

  version :large do
    process :resize_to_limit => [600, 600]
  end

  version :thumb do
    process :crop
    process :resize_to_limit => [200, 200]
  end

  def crop
    if model.crop_x.present?
      resize_to_limit(600, 600)
      manipulate! do |img|
        x = model.crop_x.to_i
        y = model.crop_y.to_i
        w = model.crop_w.to_i
        h = model.crop_h.to_i
        img.crop!(x, y, w, h)
      end
    end
  end

  after :store, :remove_original_file

  def remove_original_file(p)
    if self.version_name.nil?
      self.file.delete if self.file.exists?
    end
  end

  # Add a white list of extensions which are allowed to be uploaded.
  # For images you might use something like this:
  # def extension_white_list
  #   %w(jpg jpeg gif png)
  # end

  # Create random filename the filename of the uploaded files:
  def filename
     "#secure_token(10).#file.extension" if original_filename.present?
  end

  protected
  def secure_token(length=16)
    var = :"@#mounted_as_secure_token"
    model.instance_variable_get(var) or model.instance_variable_set(var, SecureRandom.hex(length/2))
  end
end

这是我的控制器中的更新操作:

  def update
    # respond_to do |format|
      if @person.update(person_params)
        if params[:person][:photo].present?
          render :crop
        else
          redirect_to @person, notice: "Successfully updated person."
        end
      #   format.html  redirect_to @person, notice: 'Person was successfully updated.' 
      #   format.json  head :no_content 
      # else
      #   format.html  render action: 'edit' 
      #   format.json  render json: @person.errors, status: :unprocessable_entity 
      end
    # end
  end

这是我的表格:

<%= simple_form_for @person, :html =>  :class => 'form-horizontal', :multipart => 'true'  do |f| %>


  <div class="upload">
    <!-- <div class="photo"> -->
        <%= image_tag @person.photo.url(:thumb).to_s %> 
    <!-- </div> -->
        <%= f.file_field :photo, label: 'Upload Photo' %>
    </div>

  <%= f.input :ntid, label: 'NTID:', :input_html =>  :readonly => true  %>
  <%= f.input :fname, label: 'First Name:' %>
  <%= f.input :mname, label: 'Middle Name:' %>
  <%= f.input :lname, label: 'Last Name:' %>
  <%= f.input :company, label: 'Company:' %>
  <%= f.input :department, label: 'Department:' %>
  <%= f.input :title, label: 'Title:' %>
  <%= f.input :email, label: 'E-Mail:' %>
  <%= f.input :work_phone, label: 'Work Phone:' %>
  <%= f.input :mobile, label: 'Mobile Phone:' %>
  <%= f.input :fax, label: 'FAX:' %>
  <%= f.input :office, label: 'Office:' %>
  <%= f.input :address, label: 'Address:' %>
  <%= f.input :city, label: 'City:' %>
  <%= f.input :state, collection: [ "Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", "Delaware", "District of Columbia", "Florida", "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina", "North Dakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Puerto Rico", "Rhode Island", "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virginia", "Washington", "West Virginia", "Wisconsin", "Wyoming" ], label: 'State:' %>
  <%= f.input :zipcode, label: 'Zipcode:' %>
  <%= f.input :country, priority: [ "US" ], collection: [ "Canada", "Ireland", "India", "US"], label: 'Country:' %>
  <%= f.input :suite, label: 'Suite:' %>
  <%= f.input :column, label: 'Column:' %>
  <%= f.input :assistant, label: 'Assistant:' %>

  <div class="form-actions">
    <%= f.button :submit, :class => 'btn-primary' %>
    <%= link_to t('.cancel', :default => t("helpers.links.cancel")),
                people_path, :class => 'btn' %>
  </div>
<% end %>

这是我在 development.log 中看到的内容

Started PATCH "/people/3" for 127.0.0.1 at 2014-02-13 14:47:12 -0600
Processing by PeopleController#update as HTML
  Parameters: "utf8"=>"✓", "authenticity_token"=>"et3p2hPLTKvVh7aAkD9OCq8IHJe9kZ52L/WFiNmity0=", "person"=>"crop_x"=>"200", "crop_y"=>"0", "crop_w"=>"400", "crop_h"=>"400", "commit"=>"Crop Photo", "id"=>"3"
  [1m[36mPerson Load (1.5ms)[0m  [1mSELECT "people".* FROM "people" WHERE "people"."id" = $1 LIMIT 1[0m  [["id", "3"]]
  [1m[35m (1.3ms)[0m  BEGIN
  [1m[36m (0.2ms)[0m  [1mROLLBACK[0m
Completed 500 Internal Server Error in 1430ms

NoMethodError (undefined method `body' for nil:NilClass):
  app/models/person.rb:11:in `crop_photo'
  app/controllers/people_controller.rb:49:in `update'

这是我的完整跟踪:

carrierwave (0.9.0) lib/carrierwave/storage/fog.rb:227:in `read'
carrierwave (0.9.0) lib/carrierwave/uploader/cache.rb:77:in `sanitized_file'
carrierwave (0.9.0) lib/carrierwave/uploader/cache.rb:116:in `cache!'
carrierwave (0.9.0) lib/carrierwave/uploader/versions.rb:225:in `recreate_versions!'
app/models/person.rb:11:in `crop_photo'
activesupport (4.0.2) lib/active_support/callbacks.rb:386:in `_run__335866053033251740__update__callbacks'
activesupport (4.0.2) lib/active_support/callbacks.rb:80:in `run_callbacks'
activerecord (4.0.2) lib/active_record/callbacks.rb:310:in `update_record'
activerecord (4.0.2) lib/active_record/timestamp.rb:70:in `update_record'
activerecord (4.0.2) lib/active_record/persistence.rb:477:in `create_or_update'
activerecord (4.0.2) lib/active_record/callbacks.rb:302:in `block in create_or_update'
activesupport (4.0.2) lib/active_support/callbacks.rb:383:in `_run__335866053033251740__save__callbacks'
activesupport (4.0.2) lib/active_support/callbacks.rb:80:in `run_callbacks'
activerecord (4.0.2) lib/active_record/callbacks.rb:302:in `create_or_update'
activerecord (4.0.2) lib/active_record/persistence.rb:106:in `save'
activerecord (4.0.2) lib/active_record/validations.rb:51:in `save'
activerecord (4.0.2) lib/active_record/attribute_methods/dirty.rb:32:in `save'
activerecord (4.0.2) lib/active_record/transactions.rb:270:in `block (2 levels) in save'
activerecord (4.0.2) lib/active_record/transactions.rb:326:in `block in with_transaction_returning_status'
activerecord (4.0.2) lib/active_record/connection_adapters/abstract/database_statements.rb:200:in `transaction'
activerecord (4.0.2) lib/active_record/transactions.rb:209:in `transaction'
activerecord (4.0.2) lib/active_record/transactions.rb:323:in `with_transaction_returning_status'
activerecord (4.0.2) lib/active_record/transactions.rb:270:in `block in save'
activerecord (4.0.2) lib/active_record/transactions.rb:281:in `rollback_active_record_state!'
activerecord (4.0.2) lib/active_record/transactions.rb:269:in `save'
activerecord (4.0.2) lib/active_record/persistence.rb:230:in `block in update'
activerecord (4.0.2) lib/active_record/transactions.rb:326:in `block in with_transaction_returning_status'
activerecord (4.0.2) lib/active_record/connection_adapters/abstract/database_statements.rb:202:in `block in transaction'
activerecord (4.0.2) lib/active_record/connection_adapters/abstract/database_statements.rb:210:in `within_new_transaction'
activerecord (4.0.2) lib/active_record/connection_adapters/abstract/database_statements.rb:202:in `transaction'
activerecord (4.0.2) lib/active_record/transactions.rb:209:in `transaction'
activerecord (4.0.2) lib/active_record/transactions.rb:323:in `with_transaction_returning_status'
activerecord (4.0.2) lib/active_record/persistence.rb:228:in `update'
app/controllers/people_controller.rb:49:in `update'
actionpack (4.0.2) lib/action_controller/metal/implicit_render.rb:4:in `send_action'
actionpack (4.0.2) lib/abstract_controller/base.rb:189:in `process_action'
actionpack (4.0.2) lib/action_controller/metal/rendering.rb:10:in `process_action'
actionpack (4.0.2) lib/abstract_controller/callbacks.rb:18:in `block in process_action'
activesupport (4.0.2) lib/active_support/callbacks.rb:413:in `_run__922881453698794513__process_action__callbacks'
activesupport (4.0.2) lib/active_support/callbacks.rb:80:in `run_callbacks'
actionpack (4.0.2) lib/abstract_controller/callbacks.rb:17:in `process_action'
actionpack (4.0.2) lib/action_controller/metal/rescue.rb:29:in `process_action'
actionpack (4.0.2) lib/action_controller/metal/instrumentation.rb:31:in `block in process_action'
activesupport (4.0.2) lib/active_support/notifications.rb:159:in `block in instrument'
activesupport (4.0.2) lib/active_support/notifications/instrumenter.rb:20:in `instrument'
activesupport (4.0.2) lib/active_support/notifications.rb:159:in `instrument'
actionpack (4.0.2) lib/action_controller/metal/instrumentation.rb:30:in `process_action'
actionpack (4.0.2) lib/action_controller/metal/params_wrapper.rb:245:in `process_action'
activerecord (4.0.2) lib/active_record/railties/controller_runtime.rb:18:in `process_action'
actionpack (4.0.2) lib/abstract_controller/base.rb:136:in `process'
actionpack (4.0.2) lib/abstract_controller/rendering.rb:44:in `process'
actionpack (4.0.2) lib/action_controller/metal.rb:195:in `dispatch'
actionpack (4.0.2) lib/action_controller/metal/rack_delegation.rb:13:in `dispatch'
actionpack (4.0.2) lib/action_controller/metal.rb:231:in `block in action'
actionpack (4.0.2) lib/action_dispatch/routing/route_set.rb:80:in `call'
actionpack (4.0.2) lib/action_dispatch/routing/route_set.rb:80:in `dispatch'
actionpack (4.0.2) lib/action_dispatch/routing/route_set.rb:48:in `call'
actionpack (4.0.2) lib/action_dispatch/journey/router.rb:71:in `block in call'
actionpack (4.0.2) lib/action_dispatch/journey/router.rb:59:in `each'
actionpack (4.0.2) lib/action_dispatch/journey/router.rb:59:in `call'
actionpack (4.0.2) lib/action_dispatch/routing/route_set.rb:680:in `call'
rack (1.5.2) lib/rack/etag.rb:23:in `call'
rack (1.5.2) lib/rack/conditionalget.rb:35:in `call'
rack (1.5.2) lib/rack/head.rb:11:in `call'
actionpack (4.0.2) lib/action_dispatch/middleware/params_parser.rb:27:in `call'
actionpack (4.0.2) lib/action_dispatch/middleware/flash.rb:241:in `call'
rack (1.5.2) lib/rack/session/abstract/id.rb:225:in `context'
rack (1.5.2) lib/rack/session/abstract/id.rb:220:in `call'
actionpack (4.0.2) lib/action_dispatch/middleware/cookies.rb:486:in `call'
activerecord (4.0.2) lib/active_record/query_cache.rb:36:in `call'
activerecord (4.0.2) lib/active_record/connection_adapters/abstract/connection_pool.rb:626:in `call'
activerecord (4.0.2) lib/active_record/migration.rb:369:in `call'
actionpack (4.0.2) lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
activesupport (4.0.2) lib/active_support/callbacks.rb:373:in `_run__3121532127090690729__call__callbacks'
activesupport (4.0.2) lib/active_support/callbacks.rb:80:in `run_callbacks'
actionpack (4.0.2) lib/action_dispatch/middleware/callbacks.rb:27:in `call'
actionpack (4.0.2) lib/action_dispatch/middleware/reloader.rb:64:in `call'
actionpack (4.0.2) lib/action_dispatch/middleware/remote_ip.rb:76:in `call'
actionpack (4.0.2) lib/action_dispatch/middleware/debug_exceptions.rb:17:in `call'
actionpack (4.0.2) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
railties (4.0.2) lib/rails/rack/logger.rb:38:in `call_app'
railties (4.0.2) lib/rails/rack/logger.rb:20:in `block in call'
activesupport (4.0.2) lib/active_support/tagged_logging.rb:67:in `block in tagged'
activesupport (4.0.2) lib/active_support/tagged_logging.rb:25:in `tagged'
activesupport (4.0.2) lib/active_support/tagged_logging.rb:67:in `tagged'
railties (4.0.2) lib/rails/rack/logger.rb:20:in `call'
actionpack (4.0.2) lib/action_dispatch/middleware/request_id.rb:21:in `call'
rack (1.5.2) lib/rack/methodoverride.rb:21:in `call'
rack (1.5.2) lib/rack/runtime.rb:17:in `call'
activesupport (4.0.2) lib/active_support/cache/strategy/local_cache.rb:83:in `call'
rack (1.5.2) lib/rack/lock.rb:17:in `call'
actionpack (4.0.2) lib/action_dispatch/middleware/static.rb:64:in `call'
rack (1.5.2) lib/rack/sendfile.rb:112:in `call'
railties (4.0.2) lib/rails/engine.rb:511:in `call'
railties (4.0.2) lib/rails/application.rb:97:in `call'
rack (1.5.2) lib/rack/lock.rb:17:in `call'
rack (1.5.2) lib/rack/content_length.rb:14:in `call'
rack (1.5.2) lib/rack/handler/webrick.rb:60:in `service'
/Users/scottsipiora/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/webrick/httpserver.rb:138:in `service'
/Users/scottsipiora/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/webrick/httpserver.rb:94:in `run'
/Users/scottsipiora/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/webrick/server.rb:295:in `block in start_thread'

有什么想法可以解决这个问题吗?

谢谢

【问题讨论】:

你能出示你的表格吗? 在某处调用对象的方法body,而该对象是nil。尝试找到它在哪里,可能是在布局中还是在更新视图中的其他地方? 嗨 Sergio,我到处搜索“body”,只找到有效的 和 引用。当我查看我的 development.log(我已经添加)时,我认为问题是由我在控制器中注释掉的一些行引起的(我现在正在显示)。我将它们注释掉是因为我有点菜鸟并且不认为它们是必要的,当我删除它们时,我遇到的问题得到了解决。因此,它似乎正在寻找“更新为 HTML”代码,但我已将其注释掉。我删除了它们,因为当它们在那里时,我得到了一个“AbstractController::DoubleRenderError in PeopleController#update” 你能显示完整的堆栈跟踪吗 【参考方案1】:

触发异常的实际代码在Carrierwave repository 中。 回溯查看where 它实际上被称为告诉它正在尝试缓存由于某种原因不存在的文件。调试的下一步将是实际确保您尝试重新裁剪的文件存在。我在想,因为您是在 after_updatehook 中执行此操作,所以您的文件可能在您需要的状态下不存在。

【讨论】:

当我注释掉我模型的那一行时,我没有收到任何错误(这很好)。但是,图像也不会被裁剪。嗯…… 我不能为你调试你的代码,因为我没有它不能运行它。我只能告诉你你应该在哪里寻找。 嗨,Tanel,我知道,我正在寻找。谢谢。

以上是关于Rails Carrierwave NoMethodError的主要内容,如果未能解决你的问题,请参考以下文章

Rails 4,Carrierwave,jcrop,移动到 POST,而不是 UPDATE

rails4.2.8carrierwave+mini_magick+Jcrop,图片上传失败

Rails 4.2.6 + 多态 + Carrierwave 0.10 + 条件

rails + WebRTC 录音 + Carrierwave + 雾 + S3 + Ajax 错误

Rails carrierwave 和 cloudinary 多文件上传

Rails Carrierwave NoMethodError