6

I have two models with the following structure:

class Wallet < ActiveRecord::Base
  include ActiveModel::Validations
  has_one :credit_card
  accepts_nested_attributes_for :credit_card

  validates :credit_card, :presence => true
  validates_associated :credit_card
  ...
end

class CreditCard < ActiveRecord::Base
  include ActiveModel::Validations
  belongs_to :wallet

  validates :card_number, :presence => true
  validates :expiration_date, :presence => true
  ...
end

I am testing the functionality of my application with RSpec, and I noticed something weird. If I create a Hash with attributes that don't meet the validation criteria of my nested model (such as having a nil card_number), and then try to do an update_attributes call, then what I get returned in a Wallet object with an invalid CreditCard nested model, and the appropriate errors. That is the correct, expected behavior.

If I take that same Hash though and run assign_attributes, and then save (which is all that update_attributes should be doing, then I get returned an invalid Wallet object with a completely nil nested object. Why is that? And how can I update all of the nested attribute values and check for errors without saving?

Bryce
  • 2,802
  • 1
  • 21
  • 46

3 Answers3

4

First of all - you don't need to include ActiveModel::Validations because they come with ActiveRecord::Base.

Second - yes update_attributes uses assign_attributes internally so basically it should work as expected.

If you don't have any attr_accessible, attr_protected, with/without_protection option and I assume you are creating proper hash with

{'credit_card_attributes' => {'card_number' => ''}}

then it looks like some kind of bug within rails. But at the same time I just checked it, and it seems that it works fine.

Above that if you want just to check validations without saving the object in tests, then just run

Wallet.new(hash_with_attributes).valid?

It should return proper wallet object with nested credit_card and errors on it.

Leszek Zalewski
  • 416
  • 4
  • 5
2

It sounds to me like Strong Params (Rails 4 feature) might be stripping out the nested attributes and since your validation fails without them you get redirected back to the edit page with errors and your credit card nested_attributes is now nil.

Perhaps this will help. https://stackoverflow.com/a/17532811/793330

Also save and update_attributes are not the same thing. Save will save the entire object whereas update will only change the items you pass to it that have changed. A slight difference but a difference none-the-less.

Community
  • 1
  • 1
engineerDave
  • 3,887
  • 26
  • 28
0

As I understand it, assign_attributes skips security checks.

In Rails 3, is there a difference between = and assign_attributes?

Community
  • 1
  • 1
muttonlamb
  • 6,341
  • 3
  • 26
  • 35
  • 1
    That link seems to say the opposite (that the equals sign is the function that skips security checks). And I don't get why that would result in the behavior that I am seeing. – Bryce Apr 15 '13 at 08:57