Ruby on rails Ruby:对象未由带有初始化方法的新方法实例化

Ruby on rails Ruby:对象未由带有初始化方法的新方法实例化,ruby-on-rails,ruby,Ruby On Rails,Ruby,用例:上传和处理csv文件,并在数据库中记录上传会话 方法:使用收集csv文件的新方法和创建、填充和保存上载对象的创建方法创建一个模型以保存有关上载会话的数据和一个控制器 问题:模型包含一个初始化方法(请参见模型代码),该方法似乎具有初始化对象所需的信息(请参见调试输出),但是,当控制器尝试使用模型的新方法时,该尝试不会产生有用的对象(请参见控制器代码和调试输出) 问题:创建call_history_upload对象需要更改什么 Windows 8.1上的Rails 3.2.13上的Ruby 1

用例:上传和处理csv文件,并在数据库中记录上传会话

方法:使用收集csv文件的新方法和创建、填充和保存上载对象的创建方法创建一个模型以保存有关上载会话的数据和一个控制器

问题:模型包含一个初始化方法(请参见模型代码),该方法似乎具有初始化对象所需的信息(请参见调试输出),但是,当控制器尝试使用模型的新方法时,该尝试不会产生有用的对象(请参见控制器代码和调试输出)

问题:创建call_history_upload对象需要更改什么

Windows 8.1上的Rails 3.2.13上的Ruby 1.9.3

型号代码:

class CallHistoryUpload < ActiveRecord::Base
  attr_accessible :file_name, :user_id, :record_count, :international_call_count, :unknown_client_count

  has_many :call_histories, dependent: :destroy

  require 'csv'

  def initialize( file_name, user_id )
    logger.debug( "CallHistoryUpload.initialize start")
    logger.debug( "  call_history_file  = " + file_name )
    logger.debug( "  user_id            = " + user_id )
    @file_name = file_name
    @user_id = user_id
    @record_count = 0
    @international_call_count = 0
    @unknown_client_count = 0
    logger.debug( "CallHistoryUpload.initialize end")
  end
end
class CallHistoryUpload
控制器代码:

class CallHistoryUploadsController < ApplicationController

  def get_client_id
    -1
  end

  # GET /call_history_uploads/new
  # GET /call_history_uploads/new.json
  def new
    @call_history_upload = CallHistoryUpload.new( "Unknown", session[:user_id] ) # Needed to suppoprt json

    respond_to do |format|
     format.html # new.html.erb
      format.json { render json: @call_history_upload }
    end
  end

  # POST /call_history_uploads
  # POST /call_history_uploads.json
  def create
    logger.debug( "CallHistoryUploadsController start")
    @call_history_upload = CallHistoryUpload.new( params[:call_history_file].original_filename, session[:user_id] )
    logger.debug( "CallHistoryUploadsController after instantiation")
<<This is line 24>>logger.debug( "call_history_upload.file_name = " + @call_history_upload.file_name )

    respond_to do |format|
      if @call_history_upload.save
        format.html { redirect_to @call_history_upload, notice: 'Call history upload was successful.' }
        format.json { render json: @call_history_upload, status: :created, location: @call_history_upload }
      else
        format.html { render action: "new" }
        format.json { render json: @call_history_upload.errors, status: :unprocessable_entity }
      end
    end
  end 
end
class CallHistoryUploadsController
日志输出:

Started POST "/call_history_uploads" for 127.0.0.1 at 2014-11-30 08:40:27 -0500
Processing by CallHistoryUploadsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"iDugtKa8b/U9q71Gk86sJMK6hnX1gvgQt496PX2q4Oo=", "call_history_file"=>#<ActionDispatch::Http::UploadedFile:0x4717788 @original_filename="Test_kiyvivzokpysxilfoftavyuftot.csv", @content_type="application/vnd.ms-excel", @headers="Content-Disposition: form-data; name=\"call_history_file\"; filename=\"Test_kiyvivzokpysxilfoftavyuftot.csv\"\r\nContent-Type: application/vnd.ms-excel\r\n", @tempfile=#<File:C:/Users/Gene/AppData/Local/Temp/RackMultipart20141130-5144-yn8i9>>, "commit"=>"Submit"}
CallHistoryUploadsController start
CallHistoryUpload.initialize start
  call_history_file  = Test_kiyvivzokpysxilfoftavyuftot.csv
  user_id            = KinteraAdmin
CallHistoryUpload.initialize end
CallHistoryUploadsController after instantiation
Completed 500 Internal Server Error in 0ms

NoMethodError (undefined method `has_key?' for nil:NilClass):
  app/controllers/call_history_uploads_controller.rb:24:in `create'


  Rendered C:/Ruby193/lib/ruby/gems/1.9.1/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (0.0ms)
  Rendered C:/Ruby193/lib/ruby/gems/1.9.1/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (0.0ms)
  Rendered C:/Ruby193/lib/ruby/gems/1.9.1/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (0.0ms)
2014年11月30日08:40:27-0500,127.0.0.1版开始发布“/call_history_uploads” CallHistoryUploadsController处理#创建为HTML 参数:{“utf8”=>“✓", "真实性令牌“=>”iDugtKa8b/U9q71Gk86sJMK6hnX1gvgQt496PX2q4Oo=“,“调用历史记录文件”=>,“提交”=>“提交”} CallHistoryUploadsController启动 CallHistoryUpload.initialize启动 调用_history_file=Test_kiyvivzokpysysxilfofftavyuftot.csv 用户id=KinteraAdmin CallHistoryUpload.initialize结束 实例化后的CallHistoryUploadsController 在0毫秒内完成500个内部服务器错误 NoMethodError(未定义nil:NilClass的方法'has_key'): app/controllers/call\u history\u uploads\u controller.rb:24:in'create' 呈现C:/Ruby193/lib/ruby/gems/1.9.1/gems/actionpack-3.2.13/lib/action\u dispatch/middleware/templates/rescues//u trace.erb(0.0ms) 呈现C:/Ruby193/lib/ruby/gems/1.9.1/gems/actionpack-3.2.13/lib/action\u dispatch/middleware/templates/rescues//u request\u and_response.erb(0.0ms) 呈现C:/Ruby193/lib/ruby/gems/1.9.1/gems/actionpack-3.2.13/lib/action\u dispatch/middleware/templates/rescues/diagnostics.erb在rescues/layout中(0.0ms)
部分问题似乎是您在初始化时覆盖了
ActiveRecord::Base
的正常行为。活动记录对象允许您填充对象的属性,如so
MyObject.new(属性:'value')

从对象中删除
initialize
方法,并使用

file_name = params[:call_history_file].original_filename 
user_id = session[:user_id]
CallHistoryUpload.new(file_name: file_name, user_id: user_id)

从initialize方法中调用
super
,以允许
ActiveRecord::Base
这样做

def initialize(file_name, user_id)
  logger.debug( "CallHistoryUpload.initialize start")
  logger.debug( "  call_history_file  = " + file_name )
  logger.debug( "  user_id            = " + user_id )
  @record_count = 0
  @international_call_count = 0
  @unknown_client_count = 0
  super(file_name: file_name, user_id: user_id)
  logger.debug( "CallHistoryUpload.initialize end")
end
我推荐第一种方法,因为它可以清理您的模型。如果需要为模型实例指定默认值,我建议创建一个具有描述性名称的类方法,该方法在调用
new
时设置该值,执行与第一种方法相同的指定。在初始化后使用
回调也是设置默认值的另一个选项,但要注意其后果


如果您是新手,并且正在尝试适应Rails惯例,我真的建议您阅读Rails入门指南

哦,天哪,真是一团糟。。。您应该使用组合而不是继承。第一次重构可以是:

class CallHistoryUpload < SimpleDelegator
  class Model < ActiveRecord::Base
    has_many :call_histories, dependent: :destroy
  end

  def initialize(file_name, user_id)
    logger.debug( 'CallHistoryUpload.initialize start')
    logger.debug( "  call_history_file  = #{file_name}" )
    logger.debug( "  user_id            = #{user_id}" )
    super( new_model(file_name, user_id) )
    logger.debug( "CallHistoryUpload.initialize end")
  end

  def model
    __getobj__
  end

  def self.create(file_name, user_id)
    logger.debug('CallHistoryUploadsController start')
    chu = self.new(file_name, user_id)
    logger.debug( 'CallHistoryUploadsController after instantiation')
    logger.debug( "call_history_upload.file_name = #{chu.file_name}")

    return chu
  end

  private
  def new_model(file_name, user_id)
    self.class::Model.new({
      file_name: file_name,
      user_id: user_id,
      record_count: 0,
      international_call_count: 0,
      unknown_client_count: 0,
    })
  end
end
如果您对
使用类似于
form\u的内容,您可能希望将
@call\u history\u upload.model
传递给它


始终尝试在控制器中放入尽可能少的逻辑,并将其封装在某个对象中:)

Hmmm。感谢您的关注。感谢您的关注和帮助。我不熟悉Rails。但是,我已经阅读了《Rails入门》和其他Rails指南——显然没有达到所需的效果。我写的代码遵循了在上找到的对stackoverflow问题13216976的回答。我尝试了你的建议,效果很好。非常感谢。您对我使用的参考资料的任何想法都将有助于我的学习。您看到的资源在仅使用Ruby时看起来有一个很好的答案。但是,当您添加要从ActiveRecord::Base继承的类时,您必须知道它的
  # POST /call_history_uploads
  # POST /call_history_uploads.json
  def create
    @call_history_upload = CallHistoryUpload.create( params[:call_history_file].original_filename, session[:user_id] )

    # rest of the code