Gauthier Delacroix
Gauthier Delacroix

Reputation: 709

Rails/Mongoid update_attributes ignoring persisted nested attributes validations

I've got a Mongoid "Node" model that "has_many" addresses (Address class).

I'm using a nested form to manage addresses and I'm able to create, update, destroy node's addresses successfully.

The problem is with Address validators : When validation fails on a new Address, update_attibutes fails and errors are displayed. But when trying to update an existing address with a invalid value, Address validators are triggered and fails (checked through log), but Node's update_attributes returns true and no error is displayed (the address keeps it's value unchanged).

When trying to update an existing address with invalid value and create a new invalid address at the same time to force update_attributes to fail, my form fails because of the new address, but there's no error on the existing address and its (valid) value is restored.

Is there a different behavior between new and persisted nested attributes validation ?

Here's the header of my Node class :

class Node

  # INCLUSIONS

    include Mongoid::Document
    include Mongoid::Timestamps

  # RELATIONS

    belongs_to              :organization
    has_and_belongs_to_many :platforms
    has_many                :addresses

    accepts_nested_attributes_for :addresses, allow_destroy: true, reject_if: :all_blank

Address class (class methods skipped) (note that there are overloaded getters & setters but they doesn't seem to be the cause) :

class Address

  # INCLUSIONS

    include Mongoid::Document
    include Mongoid::Timestamps

  # RELATIONS

    belongs_to :node

  # FIELDS

    field :address, type: String
    field :nat,     type: String
    field :description

  # VALIDATIONS

    validates :address, :node,
      presence: true

    # Validates address and nat validity
    validate do
      [:address, :nat].each do |field|
        errors.add(field, :invalid) unless self[field].blank? || self.class.valid_hex?(self[field])
      end
    end

  # INSTANCE METHODS

    # Address getter
    def address
      return self.class.hex_to_ip(self[:address]).to_s if self.class.valid_hex? self[:address]
      self[:address]
    end

    # Address setter
    def address= value
      self[:address] = self.class.valid_ip?(value) ? self.class.ip_to_hex(value) : value
    end

    # NAT address getter
    def nat
      return self.class.hex_to_ip(self[:nat]).to_s if self.class.valid_hex? self[:nat]
      self[:nat]
    end

    # NAT Address setter
    def nat= value
      self[:nat] = self.class.valid_ip?(value) ? self.class.ip_to_hex(value) : value
    end

end

update method of NodesController :

def update
  @node = platform.nodes.find_by name: params[:id]
  if @node.update_attributes params[:node]
    flash[:success] = t_flash :update_success, @node
    redirect_to platforms_platform_node_path(organization, platform, @node)
  else
    flash.now[:error] = t_flash :update_error, @node, count: @node.errors.count
    render :form
  end
end

I've tried adding validates_associated :addresses in Node class but it doesn't change anything (and it doesn't seem to be necessary since new addresses are validated without this).

I've also tried replacing getters & setters with after_initialize/before_save callbacks and I had the same problem.

Rails v3.2.6 / Mongoid v3.0.1

Update : params[:node] content

When submitting a new valid address (no error) :

{"name"=>"Test", "addresses_attributes"=>{"0"=>{"address"=>"1.2.3.4", "description"=>"", "nat"=>""}}}

When submitting a new address with invalid format (error successfully displayed) :

{"name"=>"Test", "addresses_attributes"=>{"0"=>{"address"=>"fdgfdgfdgfd", "description"=>"", "nat"=>""}}}

When updating a valid address with invalid value (no error bu it should) :

{"name"=>"Test", "addresses_attributes"=>{"0"=>{"id"=>"5007e1c26fad9db41f000008", "address"=>"dsfsdfsdf", "description"=>"", "nat"=>""}}}

Upvotes: 1

Views: 1623

Answers (1)

Kiran Chaudhari
Kiran Chaudhari

Reputation: 198

Check this git commit https://github.com/jiren/mongoid/commit/9ebb8af8514ea70c66a7dbe64be20bc7407a2829

You can use this gem this issue is fixed.

Upvotes: 3

Related Questions