0

I have a Company model:

class Company < ActiveRecord::Base
    has_and_belongs_to_many :jobs
    validates :name, presence: true
end

And a Job model:

class Job < ActiveRecord::Base
    has_and_belongs_to_many :companies
    validates :name, presence: true
end

All works fine except for the collection.create method. According to the Rails documentation:

The collection.create method returns a new object of the associated type. This object will be instantiated from the passed attributes, the link through the join table will be created, and, once it passes all of the validations specified on the associated model, the associated object will be saved.

This doesn't seem to work properly for me: even when the child object is invalid (and the validation works because the invalid model doesn't get saved), the association still gets created. I created this unit test to explain how I try to do it:

test "add invalid job to company" do
  company = FactoryGirl.create(:company_with_job)

  # I also tried:
  # company.jobs << FactoryGirl.build(:job, name: "")
  company.jobs.create({name: ""})
  company.save
  assert_equal 1, company.jobs.size
end

Size is instead '2' and if I inspect company.jobs I get this:

[#<Job id: 1, name: "My Job 1", created_at: "2012-11-07 10:26:10", updated_at: "2012-11-07 10:26:10">, 
#<Job id: nil, name: "", created_at: nil, updated_at: nil>]

I'm sure I'm missing something stupid, but I've been banging my head on this for a while and can't seem to understand what I'm doing wrong.

Thanks,
g

gianpi
  • 3,110
  • 1
  • 17
  • 13

1 Answers1

1

company.jobs actually contains two jobs, but one is persisted while the invalid is not.

You could test:

  • company.jobs.select(&:persisted?).size

  • company.reload.jobs.size

apneadiving
  • 114,565
  • 26
  • 219
  • 213
  • The above seems to work, I will accept this answer :) However: how can I check whether the creation was successful or not? (e.g. to know how to respond in the controller) – gianpi Nov 07 '12 at 10:48
  • `company.save` is useless in your code. check result of `company.jobs.create({name: ""})` – apneadiving Nov 07 '12 at 10:51
  • That is exactly what I tried, the problem is that it still returns a record, which has nil attributes but it's not nil itself. Is that correct? Seems weird that I have to go and check the attributes manually... – gianpi Nov 07 '12 at 10:53
  • `company.jobs.create!({name: ""})` would be an option – apneadiving Nov 07 '12 at 10:58
  • This raises an exception though... Is there no clean way to do this? With 'norma' models a call to save is simple to check, and then I can either respond with success or error. – gianpi Nov 07 '12 at 11:02
  • 1
    `job = company.jobs.build({name: ""}); job.save` – apneadiving Nov 07 '12 at 11:07