Nick
Nick

Reputation: 3160

The order in which validation and save are executed

In an integration test, I'm trying to save an invalid link. It is invalid because it links two nodes that belong to two different organizations (which my model validation does not permit). The error message displayed is however not the error message from my model validation but the error "Unable" from the controller.

I would have expected the validation from the model to come before this line in the controller. Moreover, I don't understand why, if we would take the model validation out of account, it wouldn't save. Could someone perhaps explain?


Part of my controller method:

if link.save
  render json: @organization, message: "Saved", status: :created
else
  render json: link, message: "Unable", status: :bad_request)
end

And in the Link model:

validate :same_org

def same_org
  org1 = self.first_node.organization unless self.first_node.nil?
  org2 = self.second_node.organization unless self.second_node.nil?
  unless org1 == org2
    errors.add(:second_node_id, "You can't link two nodes from different organizations")
  end
end

Upvotes: 1

Views: 141

Answers (2)

edikgat
edikgat

Reputation: 869

this happens because at your controller you don't send validation error message so, you should change your controller code to something like

if link.save
  render json: @organization, message: "Saved", status: :created
else
  render json: {errors: link.errors.full_messages, message: "Unable"}, status: :bad_request
end

Upvotes: 0

Tim
Tim

Reputation: 1005

From the api docs:

http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-save

"By default, save always run validations. If any of them fail the action is cancelled and save returns false."

So, you are correct in your assumption that validations (by default) run first. So the issue is that you are not passing that message to your view, not surprising as this line:

render json: link, message: "Unable", status: :bad_request)

Just passed back "Unable"

What you need to do is accesses the errors messages. replace "Unable" with

link.errors.full_messages.to_sentence

And you should be good.

Upvotes: 3

Related Questions