我的Rails应用程序中有代码,允许我导出CSV文件。除非有记录中包含没有值的字段,否则它可以正常工作。在那种情况下它失败了。作为一个例子,我得到的具体失败是说“没有方法错误”,它特别引用“address_line_1”,因为有些用户没有address_line_1。这只是一个例子。确实应该保护所有领域免受潜在的空白。这是代码:
def download_kids_csv
@csv_headers = ['First',
'Last',
'Child First',
'Child Last',
'Parent Email',
'School',
'Class',
'Address',
'City',
'State',
'Zip',
'Parent Phone']
@kid_data = []
@school = School.find(params[:school_id])
@school.classrooms.each do |classroom|
classroom.kids.includes(:users).each do |kid|
kid.users.each do |parent|
@kid_data << {
first: parent.first_name,
last: parent.last_name,
child_first: kid.first_name,
child_last: kid.last_name,
parent_email: parent.email,
school: @school.name,
class: classroom.classroom_name,
address: parent.addresses.first.address_line_1,
city: parent.addresses.first.city,
state: parent.addresses.first.state,
zip: parent.addresses.first.zip_code,
parent_phone: parent.phones.first.phone_number
}
end
end
end
respond_to do |format|
format.csv do
headers['Content-Disposition'] = "attachment; filename=\"#{@school.name.downcase.gsub(' ', '-')}-data.csv\""
headers['Content-Type'] ||= 'text/csv'
end
end
end
答案 0 :(得分:0)
好的,你得到的问题是因为你在nil值上调用方法。
例如,当你这样做时:
kid.first_name
并且孩子没有你这样做
nil.first_name
nil没有实现first_name
方法,因此会抛出错误。你可以做些什么来规避这个(它有点难看)就是这个
kid.try(:first_name)
这将阻止您形成获取这些方法缺失的错误
对于那些长链,您可以执行以下操作
parent.try(:addresses).try(:first).try(:zip_code)
这可以为您节省很多麻烦,但问题的根本原因是数据完整性,如果您确保数据不是空白,则不必执行所有这些操作。然而,我确实在现实世界中理解说起来容易做起来难。我可以给你一个关于The Law of Demeter
的演讲,以及你如何不跨越对象来访问他们的属性,以及代码如何闻到错误的数据组织,但它是一个电子表格,有时你只需要数据。祝你好运!
答案 1 :(得分:0)
要构建早期的答案,如果你使用的是Ruby 2.3,你也可以利用所谓的孤独运算符&.
。
示例如下所示:kid&.first_name
。
如果你还没有使用那个版本的ruby,那么有一个很好的gem可以帮助你解决这个比.try
更强大的情况。
使用该gem,您的代码看起来像kid.andand.first_name
。在这种情况下可能有些过分,但这里的区别在于,如果first_name
不是nil,它只会执行kid
方法调用。对于较长的链parent.address.first.zip_code
,这意味着如果parent
为nil,则函数链会立即退出,而不是通过try调用所有不同的属性。
答案 2 :(得分:0)
是否可以使用除非或其他条件?
unless parent.addresses.first.address_line_1.blank?
address: parent.addresses.first.address_line_1,
end
或
if parent.addresses.first.address_line_1 != nil
address: parent.addresses.first.address_line_1,
else
address: nil || "address is empty"
end