使用案例:上传并处理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 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
日志输出:
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)
答案 0 :(得分:1)
天啊,多么糟糕......你应该使用构图而不是继承。第一次重构可能是:
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
在控制器中,我们只更改创建:
# 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
如果您使用form_for
之类的内容,则可能需要将@call_history_upload.model
传递给它。
总是尽量在控制器中放置尽可能少的逻辑并将其封装在某个对象中:)
答案 1 :(得分:0)
部分问题似乎是你在初始化时凌驾于ActiveRecord::Base
的正常行为。活动记录对象允许您填充对象的属性,如MyObject.new(property: '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)
或
在初始化方法中调用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
时设置此值,并执行与第一种方法相同的赋值。使用after_initialize
回调也可以设置默认值,但要注意它的后果。
如果您是新手并且正在尝试习惯Rails约定,我建议您阅读Rails入门指南。