ActiveRecord :: AssociationTypeMismatch gotNilClass

时间:2016-07-20 14:28:47

标签: ruby-on-rails ruby ruby-on-rails-3 activerecord

我是Ruby和Ruby on Rails的初学程序员,我正在尝试在我的任务中运行rake命令,但是当我执行以下操作时:

rake daily_tasks:process_api

rake aborted!
ActiveRecord::AssociationTypeMismatch: Estado(#47392639701120) expected, got NilClass(#47392580444120)
/home/thiagoamaralr/Desktop/proponente-master-4f8a3b2ddb02a90b2c173cf31383505018d02dd/app/services/create_programa_api.rb:21:in `call'
/home/thiagoamaralr/Desktop/proponente-master-74f8a3b2ddb02a90b2c173cf31383505018d02dd/lib/tasks/daily_tasks.rake:7:in `block (3 levels) in <top (required)>'
/home/thiagoamaralr/Desktop/proponente-master-74f8a3b2ddb02a90b2c173cf31383505018d02dd/lib/tasks/daily_tasks.rake:5:in `each'
/home/thiagoamaralr/Desktop/proponente-master-74f8a3b2ddb02a90b2c173cf31383505018d02dd/lib/tasks/daily_tasks.rake:5:in `block (2 levels) in <top (required)>'
Tasks: TOP => daily_tasks:process_api
(See full trace by running task with --trace)

按照我正在尝试运行的任务:

namespace :daily_tasks do
  desc "Process the day to day tasks"
  task process_api: :environment do

    SiconvApi::Programa.find.each do |programa|
      if programa.data_inicio_recebimento_propostas && (programa.data_inicio_recebimento_propostas.to_date >= Date.parse("2015/06/01"))
        CreateProgramaApi.call(SiconvApi::Serializers::Programa.new(programa))
      end
    end
  end
end

这是内容create_programa_api.rb:

class CreateProgramaApi
  def self.call(programa_api)
    params = programa_api.to_h
    params[:orgao] = Orgao.where("lower(name) = ?", programa_api[:orgao][:nome].mb_chars.downcase).first_or_create(name: programa_api[:orgao][:nome])
    params[:orgao_vinculado] = Orgao.where("lower(name) = ?", programa_api[:orgao_vinculado][:nome].mb_chars.downcase).first_or_create(name: programa_api[:orgao_vinculado][:nome])
    params[:orgao_executor] = Orgao.where("lower(name) = ?", programa_api[:orgao_executor][:nome].mb_chars.downcase).first_or_create(name: programa_api[:orgao_executor][:nome])
    params[:estados] = []
    if programa_api[:estados].size == 27
      params[:estados] << Estado.find_by(sigla: 'Todos')
    else
      programa_api[:estados].each do |e|
        params[:estados] << Estado.find_by(sigla: e)
      end
    end
    params[:atendes] = [Atende.where("lower(name) = ?", programa_api[:atende_a].mb_chars.downcase).first_or_create(name: programa_api[:atende_a])] if programa_api[:atende_a]
    params.delete(:atende_a)
    programa = Programa.find_by(codigo: programa_api[:codigo])
    if programa
      programa.update(params)
    else
      Programa.create! params
    end
  end
end

感谢您的关注!

2 个答案:

答案 0 :(得分:0)

nil中有params[:estados]个对象,Rails无法保存此关联。 删除它们的最简单方法是在第14行之后调用params[:estados].compact!

答案 1 :(得分:0)

这段代码是你的问题:

params[:estados] = []
if programa_api[:estados].size == 27
  params[:estados] << Estado.find_by(sigla: 'Todos')
else
  programa_api[:estados].each do |e|
    params[:estados] << Estado.find_by(sigla: e)
  end
end

如果未找到记录,#find_by将返回nil。这就是您收到错误的原因:

ActiveRecord::AssociationTypeMismatch: Estado(#47392639701120) expected, got NilClass

致电Programa.create!(params)

一种解决方案是在params[:estados].compact!语句后调用if(这是使用Array#compact!删除任何nil值。)

或者,您可以改为编写代码段,如下所示:

params[:estados] = Estadio.where(
  sigla: (programa_api[:estados].size == 27 ? 'Todos' : programa_api[:estados])
)

使用此代码,不再需要调用compact!,因为如果没有找到记录,我们最终会得到数组(即没有{{1} }))。

请注意,此处的行为相当不相同 - 如果有多个nil记录且Estado等于sigla之一,则会发生什么?还是programa_api[:estados]?以前你只是获取“第一个”这样的记录,而现在你将获取所有。这可能不是问题(或者甚至可能是正确的行为!!) - 至少应该注意这一点。