Empty association_attributes for validation testing

28 views
Skip to first unread message

Javix

unread,
Mar 25, 2013, 5:47:27 AM3/25/13
to rs...@googlegroups.com
Sorry if it is rails talk group issue.
I can't figure how to empty the association_attributes in one of the specs for testing if the object is valid.
So, I have the following models:

#timesheet.rb

class Timesheet < ActiveRecord::Base
  attr_accessible :status, :user_id, :start_date, :end_date, :activities_attributes
  has_many :activities, dependent: :destroy
  has_many :time_entries, through: :activities
end

#activity.rb
class Activity < ActiveRecord::Base
  attr_accessible :task_id, :timesheet_id, :time_entries_attributes
  validates :task_id, presence: true
  belongs_to :timesheet
  belongs_to :task
  has_many :time_entries, order: :workdate, dependent: :destroy
 accepts_nested_attributes_for :time_entries, allow_destroy: true, reject_if: proc { |a| a[:worktime].blank? }
end

I create a timsheet, activity and time entry by using nested forms. It works as needed.
But for testing the below spec fails:

#timesheet_spec.rb

describe Timesheet do
  before { @timesheet = build(:submitted_timesheet) }
 
  subject { @timesheet }
...
describe "when activities attributesis empty" do
    before { @timesheet.activities_attributes = {} }
    it { should_not be_valid }
  end
end

The same is in the console:

irb(main):002:0> t = FactoryGirl.build(:submitted_timesheet)
irb(main):003:0> t.activities
=> [#<Activity id: nil, timesheet_id: nil, task_id: 4, created_at: nil, updated_at: nil>]
irb(main):004:0> t.valid?
=> true
irb(main):005:0> t.activities_attributes = {}
=> {}
irb(main):006:0> t.activities
=> [#<Activity id: nil, timesheet_id: nil, task_id: 4, created_at: nil, updated_at: nil>]
irb(main):007:0> t.valid?
=> true

Any idea on how to 'invalidated' the association_attributes to make it pass ?

Thanks and regards.

David Chelimsky

unread,
Mar 25, 2013, 8:00:29 AM3/25/13
to rs...@googlegroups.com
Please post the failure message.

Javix

unread,
Mar 25, 2013, 8:29:06 AM3/25/13
to rs...@googlegroups.com


Please post the failure message.

describe "when activities attributes is empty" do

    before { @timesheet.activities_attributes = {} }
    it { should_not be_valid }   
  end
...

Output:

 when activities attributes is empty
    should not be valid (FAILED - 1)
...

Failures:

  1) Timesheet when activities attributes is empty
     Failure/Error: it { should_not be_valid }
       expected valid? to return false, got true
     # ./spec/models/timesheet_spec.rb:39:in `block (3 levels) in <top (required)>'

Finished in 2.69 seconds
45 examples, 1 failure

Failed examples:

rspec ./spec/models/timesheet_spec.rb:39 # Timesheet when activities attributes is empty 

The only way I found for the moment is to build a timesheet with ONe and the only activity, then setting its task to nil as follows:

describe "when the task is not present" do
    before  { @timesheet.activities.first.task = nil }     
    it { should_not be_valid }
  end

Far from being perfect, agreed. So any idea would be really appreciated.
Thanks and regards

Javix

unread,
Mar 25, 2013, 8:37:41 AM3/25/13
to rs...@googlegroups.com
In fact, when playing in the console, I could see that assigning association_attributes an empty hash does not empty task_id:

irb(main):001:0> require 'factory_girl_rails'
=> true
irb(main):002:0> t=FactoryGirl.build(:submitted_timesheet)
irb(main):004:0> t.activities

=> [#<Activity id: nil, timesheet_id: nil, task_id: 4, created_at: nil, updated_at: nil>]
irb(main):003:0> t.activities_attributes = {}
=> {}
irb(main):004:0> t.activities

=> [#<Activity id: nil, timesheet_id: nil, task_id: 4, created_at: nil, updated_at: nil>]

I believed that it would be the case ...

Dan Brooking

unread,
Mar 25, 2013, 8:39:12 AM3/25/13
to rs...@googlegroups.com
Just a shot in the dark as I'm not a rails expert... But it doesn't look like your code required timesheet to have activities_attributes?

Do you need to add this:
  validates :activities_attributes, presence: true

to the model?
--
You received this message because you are subscribed to the Google Groups "rspec" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rspec+un...@googlegroups.com.
To post to this group, send email to rs...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msg/rspec/-/18oHzvGc1GYJ.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

dchel...@gmail.com

unread,
Mar 25, 2013, 8:55:46 AM3/25/13
to rs...@googlegroups.com
Another shot in the dark:

My guess is that there is `activities_attributes` method to begin with and Rails generates it for you the first time it is called. By setting timesheet.activities_attributes = {}, you're assigning a value to a previously non-existent variable that is not used internally in validations.

Part of the problem here, IMO, is an overuse of "reuse". You're creating a valid instance and then changing its state in order to make it invalid. I think it would be easier to understand if you created an invalid instance, e.g.

describe Timesheet do
  it "is invalid when any of its activities has no tasks" do
    timesheet = Timesheet.new
    timesheet.activities << Activity.new
    expect(timesheet).not_to be_valid
  end
end

You can do that using subject and/or before if you like, but this is very explicit and easy to reason about as/is.
To unsubscribe from this group and stop receiving emails from it, send an email to rspec+unsubscribe@googlegroups.com.

David Chelimsky

unread,
Mar 25, 2013, 8:56:23 AM3/25/13
to rs...@googlegroups.com
That should have been "there is _no_ `activities_attributes` method to
begin with".
>>> email to rspec+un...@googlegroups.com.
>>> To post to this group, send email to rs...@googlegroups.com.
>>> To view this discussion on the web visit
>>> https://groups.google.com/d/msg/rspec/-/18oHzvGc1GYJ.
>>> For more options, visit https://groups.google.com/groups/opt_out.
>>>
>>>
>
> --
> You received this message because you are subscribed to the Google Groups
> "rspec" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to rspec+un...@googlegroups.com.
> To post to this group, send email to rs...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/rspec/-/pGAJvG4SkiMJ.

Javix

unread,
Mar 25, 2013, 10:10:39 AM3/25/13
to rs...@googlegroups.com


On Monday, March 25, 2013 1:56:23 PM UTC+1, dchel...@gmail.com wrote:
That should have been "there is _no_ `activities_attributes` method to
begin with".

On Mon, Mar 25, 2013 at 7:55 AM, dchel...@gmail.com
<dchel...@gmail.com> wrote:
> Another shot in the dark:
>
> My guess is that there is `activities_attributes` method to begin with and
> Rails generates it for you the first time it is called. By setting
> timesheet.activities_attributes = {}, you're assigning a value to a
> previously non-existent variable that is not used internally in validations.
>
> Part of the problem here, IMO, is an overuse of "reuse". You're creating a
> valid instance and then changing its state in order to make it invalid. I
> think it would be easier to understand if you created an invalid instance,
> e.g.
>
OK, I got it, - the below is the spec for building a new Timesheet with no activity selected/set up for a new Timesheet:
> describe Timesheet do
>   it "is invalid when any of its activities has no tasks" do
>     timesheet = Timesheet.new
>     timesheet.activities << Activity.new
>     expect(timesheet).not_to be_valid
>   end
> end
>
I tested that and it worked either with defining it directly in the spec or creating just a separate factory with no activity task.
Now I see the difference with my another spec where I just set to nil all the created activities in the timesheet factory:

describe "when no activities present" do
    before  do
      @timesheet.activities.each { |activity| activity.task = nil }     
    end
    it { should_not be_valid }
  end

Thank you all for the time and help.

Best regards
The second situation is when 'emptying' all the
Reply all
Reply to author
Forward
0 new messages