I've a Register model which has_many :telephones Register model accepts_nested_attributes_for :telephones, :reject_if number and code blank?, and has attr_accessible :telephones_attributes (and all other fields)
Telephones belongs_to :register and has attr_accessible for all fields
When the form sends the params, it seems to be well formed, but when the form fields are sent to @register.attributes = params[:register] it will update all fields but not the existing telephones(which should have gotten an update to its fields as well), they just stay the way they were before(I checked when debugging)
Now this is where it gets weird, in the console when I test it, I was thinking it was something about params, because I could make it work there, now I discovered it behaves like I want for the has_many association only after the first time I try to assign it, I tried this in controller(mass assigning params two times) and it works.
Of course it must have something to do with the fact that I'm using model.attributes = params to assign, Im doing it this way so I can also save a monitoring of the changes to the system(and I'm not doing this in before_filters because I have to access some data I feel is specific to the controller like current_user and on) maybe is poor design... but isn't it weird?I have to mass-assign two times for this to work? Is this some kind of bug? Does anyone know if there's a way to fix it?
- I'm on rails 2.3.8, ruby 1.8.6
Edit: Here's sample code, a lot of this code here is in portuguese, tho :/
telefone = telephones, cadastro = register
As you can see I've got an all_changes method that aggregates changes done to some associations, theres a custom setter for comments(comentario_interno/externo) as means to adding one comment at time...
#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]}