Ошибка? Я должен массово назначить параметры два раза, чтобы обновить ассоциацию has_many

У меня есть модель Register, в которой has_many:telephones Модель регистра accepts_nested_attributes_for:telephones,:reject_if number and code blank?, и имеет attr_accessible:telephones_attributes (и все другие поля)

Телефоны принадлежат: регистрируются и имеют атрибут attr_accessible для всех полей

Когда форма отправляет параметры, она кажется правильно сформированной, но когда поля формы отправляются на @register.attributes = params[:register], она обновит все поля, но не существующие телефоны (которые должны были получить обновление для поля тоже), они просто остаются прежними (я проверял при отладке)

Вот когда это становится странным, в консоли, когда я тестировал его, я думал, что это что-то с параметрами params, потому что я мог заставить его работать там, теперь я обнаружил, что он ведет себя так, как я хочу для ассоциации has_many, только после первого раза Я пытаюсь назначить это, я попробовал это в контроллере (массовое назначение параметров два раза), и это работает.

Конечно, это должно быть как-то связано с тем фактом, что я использую model.attributes = params для назначения, я делаю это таким образом, чтобы я также мог сохранить мониторинг изменений в системе (и я этого не делаю в before_filters, потому что я должен получить доступ к некоторым данным, которые, как мне кажется, специфичны для контроллера, например current_user и on), может быть, плохой дизайн... но разве это не странно? Мне нужно назначить два раза, чтобы это работало? Это какая-то ошибка? Кто-нибудь знает, есть ли способ это исправить?

  • Я на рельсах 2.3.8, рубин 1.8.6

Изменить: Вот пример кода, большая часть этого кода здесь на португальском языке, tho:/

телефон = телефоны, кадастр = регистрация

Как вы можете видеть, у меня есть метод all_changes, который агрегирует изменения, внесенные в некоторые ассоциации, есть пользовательский установщик для комментариев (comentario_interno/externo) как средство добавления одного комментария за раз...

    #models

class Telefone < ActiveRecord::Base
  #relações
  belongs_to :cadastro
  #validações
  validates_presence_of :ddd
  validates_presence_of :numero
  validates_numericality_of :ddd
  validates_numericality_of :numero

  attr_accessible :ddd, :numero, :cadastro_id, :id

end

class Cadastro < ActiveRecord::Base
  #relações
  #cliente
  belongs_to :estado
  belongs_to :indicacao
  has_many :telefones
  has_one :outra_indicacao
  #venda
  belongs_to :user
  belongs_to :banco
  belongs_to :plano
  belongs_to :pacote
  belongs_to :situacao
  belongs_to :situacao_diversa
  has_many :comentario_internos
  has_many :comentario_externos

  #system
  #has_many :sys_logs
  has_many :sys_logs, :as => :monitorable
  has_many :email_history, :through => :sys_logs, :conditions => {:type => 'SysEmail'} , :source => :sys_actions
  has_many :lock_history, :through => :sys_logs, :conditions => {:type => 'SysLock'}, :source => :sys_actions
  has_many :alteracao_history, :through => :sys_logs, :conditions => {:type => 'SysAlteracao'}, :source => :sys_actions

  #filtros

  #validações
  #cliente
  validates_presence_of :tipo, :nome, :cpfcnpj, :rg, :data_nascimento, :profissao, :filiacao, :email, :logradouro,
                        :tp_logradouro, :numero, :bairro, :cep, :cidade
  validates_uniqueness_of :cpfcnpj
  validates_presence_of :estado
  #validate :must_have_at_least_one_telephone
  #venda
  validates_presence_of :user
  validates_presence_of :situacao
  validates_numericality_of :agencia, :allow_blank => true
  validates_numericality_of :digito_agencia, :allow_blank => true
  validates_numericality_of :cc, :allow_blank => true
  validates_numericality_of :digito_cc, :allow_blank => true
  validates_numericality_of :cpf_titular, :allow_blank => true
  #cpf must be unique




  accepts_nested_attributes_for :telefones, :reject_if => lambda {|attr| attr['ddd'].blank? && attr['numero'].blank?}
  accepts_nested_attributes_for :outra_indicacao
  accepts_nested_attributes_for :comentario_internos, :reject_if => lambda {|attr| attr['comentario'].blank?}
  accepts_nested_attributes_for :comentario_externos, :reject_if => lambda {|attr| attr['comentario'].blank?}

  #attr_accessible :new_comentario_interno, :new_comentario_externo, :telefones_attributes

  attr_accessible :telefones_attributes, :new_comentario_interno, :new_comentario_externo, :outra_indicacao_attributes,
                  :user_id, :cc, :digito_cc, :data_instalacao, :cpfcnpj, :profissao, :tp_logradouro, :agencia, :cpf_titular,
                  :situacao_id, :estado_id, :plano_id, :banco_id, :nome, :data_nascimento, :cep, :observacao, :data_agendamento,
                  :dia_vencimento, :digito_agencia, :pacote_id, :nome_titular, :logradouro,
                  :indicacao_id, :telefones_attributes, :contrato, :confirmacao_condicoes, :estado_civil, :cidade,
                  :horario_retorno, :tipo, :sexo, :filiacao, :complemento, :bairro, :rg, :expeditor, :email, :numero,
                  :situacao_diversa_id

  def new_comentario_interno=(attributes = {})
    self.comentario_internos << ComentarioInterno.new(:user_id => attributes[:user_id], :comentario => attributes[:comentario]) unless attributes[:comentario].blank?
  end

  def new_comentario_externo=(attributes = {})
    self.comentario_externos << ComentarioExterno.new(:user_id => attributes[:user_id], :comentario => attributes[:comentario]) unless attributes[:comentario].blank?
  end

  def self.buscar_cadastros(options = {})
    conditions = []
    conditions << sanitize_sql(["cadastros.situacao_id = ?", options[:situacao_id]]) unless options[:situacao_id].blank?
    conditions << sanitize_sql(["cadastros.user_id = ?", options[:user_id]]) unless options[:user_id].blank?
    conditions << sanitize_sql(["cadastros.created_at >= ? AND cadastros.created_at < ?",
                                Date.civil(options[:ano].to_i, options[:mes].to_i, 1),
                                Date.civil(options[:ano].to_i, options[:mes].to_i, -1)]) unless options[:ano].blank? || options[:mes].blank?

    self.find(:all, :conditions => conditions.join(" AND "))
  end

  def self.vendas_count_on(situacao_id, options = {})
    select = sanitize_sql(["SELECT count(*) FROM cadastros LEFT JOIN situacaos ON cadastros.situacao_id = situacaos.id
    WHERE situacaos.id = ?", situacao_id])
    select << sanitize_sql([" AND cadastros.user_id = ?", options[:user_id]]) unless options[:user_id].blank?
    select << sanitize_sql([" AND cadastros.created_at >= ? AND cadastros.created_at < ?",
                            Date.civil(options[:ano].to_i, options[:mes].to_i, 1),
                            Date.civil(options[:ano].to_i, options[:mes].to_i, -1)]) unless options[:ano].blank? || options[:mes].blank?

    count_by_sql(select)
  end

  def all_changes
    #agregar telefones, outra indicacao, comentarios internos, comentarios externos
    changes = self.changes
    h = Hash.new
    h["outra_indicacao"] = self.outra_indicacao.descricao_change if self.outra_indicacao && self.outra_indicacao.changed?

    if self.id
      old_telefones = connection.execute("select ddd || '-' || numero as numformat from telefones where cadastro_id = #{self.id}").collect {|t| t["numformat"]}
    else
      old_telefones = []
    end
    new_telefones = self.telefones.collect {|t| "#{t.ddd}-#{t.numero}"}
    h["telefones"] = [old_telefones.join(', '), new_telefones.join(', ')] unless (old_telefones - new_telefones).empty?
    changes.delete("syslogid")
    changes.merge(h)
  end

  def locked?
    #pegar o ultimo lock e retornar o valor
    last_lock = self.lock_history.last
    if last_lock
      return last_lock.locked?
    else
      return false
    end
  end

end

#here's what Ive got to do in controller for this to work, remember its only when updating existing phones, creating is working normally

@cadastro.attributes = params[:cadastro]
    @cadastro.attributes = {:telefones_attributes => params[:cadastro][:telefones_attributes]}

1 ответ

В вашем примере неясно, как используется all_changes или даже вызывается ли он. Попробуйте упростить ваш код, чтобы увидеть, действительно ли проблема связана с Rails или с вашей реализацией. Например, должно работать следующее:

class Telefone < ActiveRecord::Base
  belongs_to :cadastro
  validates_presence_of :ddd
  validates_presence_of :numero
  validates_numericality_of :ddd
  validates_numericality_of :numero
end

class Cadastro < ActiveRecord::Base
  has_many :telefones

  accepts_nested_attributes_for :telefones
end

@cadastro.attributes = {:telefones_attributes => [{:ddd => 111, :numero => 1234567}]}
@cadastro.save

Вы также должны заметить, что вам не нужно условие reject_if в вашем accepts_nested_attributes_for, потому что вы уже проверяете наличие: ddd и: Numberro в базовом классе.

Другие вопросы по тегам