nil的未定义方法`map':在rails中使用paperclip时的NilClass

时间:2014-05-04 16:09:12

标签: ruby-on-rails paperclip

我在rails项目中遇到了一个很棒的错误。我有一个控制器=> prdocuts_controller.rb。我想在创建新产品时使用options_from_collection_for_select。当我创建新产品时,每件事情都可以,我可以这样做,但当我添加file_field将图片上传到产品时,我会收到以下错误:

NoMethodError in Products#create
undefined method `map' for nil:NilClass

当我删除file.field时,每件事情都会好起来,新产品会保存到数据库中。

products_controller.rb

class ProductsController < ApplicationController
  before_action :set_product, only: [:show, :edit, :update, :destroy]
  layout "product"
  # GET /products
  # GET /products.json
  def index
    @categories = Category.all
    @products = Product.all
  end

  # GET /products/1
  # GET /products/1.json
  def show
  end

  # GET /products/new
  def new
    @categories = Category.all
    @product = Product.new
  end

  # GET /products/1/edit
  def edit
    @categories = Category.all
    @product = Product.all
  end

  # POST /products
  # POST /products.json
  def create
    @product = Product.new(product_params)
    @product.responsibility = current_user.responsibility
    @product.date_time = Time.now

    respond_to do |format|
      if @product.save
        format.html { redirect_to @product, notice: 'Product was successfully created.' }
        format.json { render action: 'show', status: :created, location: @product }
      else
        format.html { render action: 'new' }
        format.json { render json: @product.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /products/1
  # PATCH/PUT /products/1.json
  def update
    respond_to do |format|
      if @product.update(product_params)
        format.html { redirect_to @product, notice: 'Product was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: 'edit' }
        format.json { render json: @product.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /products/1
  # DELETE /products/1.json
  def destroy
    @product.destroy
    respond_to do |format|
      format.html { redirect_to products_url }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_product
      @product = Product.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def product_params
      params.require(:product).permit(:category_id, :name, :code, :date_time, :describe, :picture)
    end
end

product.rb

class Product < ActiveRecord::Base
  has_attached_file :picture, :styles => { :medium => "300x300>", :thumb => "100x100>" }, :default_url => "/images/missing.png"
  belongs_to :category
end

视图/产品/ new.html.erb

<%= form_for @product, :html => {multipart: true} do |f| %>
    <% if @product.errors.any? %>
        <div id="error_explanation">
          <h2><%= pluralize(@product.errors.count, "error") %> prohibited this product from being saved:</h2>

          <ul>
            <% @product.errors.full_messages.each do |msg| %>
                <li><%= msg %></li>
            <% end %>
          </ul>
        </div>
    <% end %>
      <div class="control-group">
        <label class="control-label">Product Name</label>
        <%= f.text_field :name, :class => "m-wrap span8", :placeholder => "enter product name" %>
      </div>
      <div class="control-group">
        <label class="control-label">Product Code</label>
        <%= f.text_field :code, :class => "m-wrap span8", :placeholder => "enter product code" %>
      </div>

      <div class="control-group">
        <label class="control-label" >Category</label>
        <div class="controls">
          <div class="select2-wrapper">
            <select name="product[category_id]" class="select2_category m-wrap span8">
              <%= options_from_collection_for_select(@categories,:id, :name,@product.category_id) %>
            </select>
          </div>
        </div>
      </div>

      <div class="control-group">
        <label class="control-label">Product Code</label>
        <%= f.text_area :describe, :class => "m-wrap span8", :placeholder => "enter describe" %>
      </div>
      <br/>
      <%= f.file_field :picture %>
      <br/>
      <div class="action">
        <%= f.submit "Save change", :class => "btn green" %>
      </div>
<% end %>

系统日志:

User Load (0.0ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 17 ORDER BY "users"."id" ASC LIMIT 1
Command :: identify -format '%wx%h,%[exif:orientation]' "C:/Users/MGH~1.119/AppData/Local/Temp/6f87f43a62513173b9edfea7b58ee2d020140504-660-1luu1b5.jpg[0]" 2>NUL
[paperclip] An error was received while processing: #<Paperclip::Errors::NotIdentifiedByImageMagickError: Paperclip::Errors::NotIdentifiedByImageMagickError>
Command :: identify -format '%wx%h,%[exif:orientation]' "C:/Users/MGH~1.119/AppData/Local/Temp/6f87f43a62513173b9edfea7b58ee2d020140504-660-1luu1b5.jpg[0]" 2>NUL
[paperclip] An error was received while processing: #<Paperclip::Errors::NotIdentifiedByImageMagickError: Paperclip::Errors::NotIdentifiedByImageMagickError>
  Responsibility Load (3.0ms)  SELECT "responsibilities".* FROM "responsibilities" WHERE "responsibilities"."user_id" = ? ORDER BY "responsibilities"."id" ASC LIMIT 1  [["user_id", 17]]
   (0.0ms)  begin transaction
   (0.0ms)  rollback transaction
[deprecated] I18n.enforce_available_locales will default to true in the future. If you really want to skip validation of your locale you can set I18n.enforce_available_locales = false to avoid this message.
  Rendered products/_form.html.erb (12.0ms)
  Rendered products/new.html.erb within layouts/product (13.0ms)
Completed 500 Internal Server Error in 132ms

ActionView::Template::Error (undefined method `map' for nil:NilClass):
    27:         <div class="controls">
    28:           <div class="select2-wrapper">
    29:             <select name="product[category_id]" class="select2_category m-wrap span8">
    30:               <%= options_from_collection_for_select(@categories,:id, :name,@product.category_id) %>
    31:             </select>
    32:           </div>
    33:         </div>

我使用'paperclip','〜&gt;这个项目中的3.0'。任何人都可以帮我找到问题吗?

2 个答案:

答案 0 :(得分:1)

错误的原因是@categories为零。由于ImageMagick错误导致您的产品无法保存,因此当您返回显示视图时@categories未定义。

您需要包含

@categories = Category.all
在保存失败的情况下,在create方法中

。或者考虑控制器中的before_filter,这样您就可以避免在所有操作中重复代码。

为什么首先出现ImageMagick错误是另一回事,但这是导致map错误的原因。 Paperclip将抛出NotIdentifiedByImageMagickError错误,其中ImageMagick无法解析文件 - 通常是因为它不是有效图像。您可以在命令行中对此进行测试。

答案 1 :(得分:0)

#map处理此行时,可以在内部调用

new.html.erb

<%= options_from_collection_for_select(@categories,:id, :name,@product.category_id) %>

我猜它是在@categories上调用的。

问题在于:
当用户请求/new页面时,系统会处理new操作,并且@categories通常会初始化。
但是,当您render 'new'中的create时,Rails将在不经过控制器中的操作的情况下呈现该模板,因此@categories将为nil

尝试:

def new
  @categories = Category.all
  @product = Product.new
end


def create
  @product = Product.new(product_params)
  @product.responsibility = current_user.responsibility
  @product.date_time = Time.now

  respond_to do |format|
    if @product.save
      format.html { redirect_to @product, notice: 'Product was successfully created.' }
      format.json { render action: 'show', status: :created, location: @product }
    else
      format.html {
        @categories = Category.all
        render action: 'new'
      }
      format.json { render json: @product.errors, status: :unprocessable_entity }
    end
  end
end