Question

I have an Invoice (belongs_to :contact) and a Contact (has_many :invoices). In a new invoice form I want to reference which contact it belongs to. For that purpose, the following field:

<input name='invoice[contact]' type='text'>

Which works when I write the contact's id. No problems there. However, I want it to work with the contact's name. So I added the following callback in Invoice:

before_save do |invoice|
  invoice.contact = Contact.find_by(name: invoice.contact)
end

However, invoice.contact turns out to be nil (despite the input field not being empty) which throws an error as there's no contact with name: nil.

The following work:

before_save do |invoice|
  invoice.contact = Contact.find_by(name: 'some name')
end

and

before_save do |invoice|
  invoice.contact = Contact.find('52a233b585c4f0fa7d000001')
end

This leads me to believe that there's a setter for invoice.contact but not a getter.

Any thoughts?

Was it helpful?

Solution

I think you'll have better luck if you use a virtual attribute for the name, otherwise I think you'll run into problems when someone tries to treat a name like 'Bob Dobbs' as an ObjectId. Something like this in your form:

<input name='invoice[contact_name]' type='text'>

and then in your Mongoid model:

attr_reader :contact_name
attr_accessible :contact_name
before_save do |invoice|
  invoice.contact = Contact.find_by(name: invoice.contact_name)
end

That should get you the contact name in invoice_contact_name as a String and nothing will try to interpret it as anything other than a string.

I'd probably drop the before_save hook and move the Contact.find_by into a before_validation instead, then you can validate that you have a contact_id and have a chance to detect a bad contact_name:

attr_reader :contact_name
attr_accessible :contact_name
before_validation :lookup_contact_name
validate_presence_of :contact_id

def lookup_contact_name
  # Some sort of `contact_name` cleanup might be a good idea in here too.
  self.contact = Contact.find_by(name: contact_name)
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top