16

I am trying to add a new entry in my database for a model that has a belongs_to relationship. I have 2 models, Jobs and Clients.

It was easy enough to find tutorial on how to set up the association between these two (using has_many and belongs_to), but I can't seem to find any examples where the association is actually used.

In my code, I am trying to create a new job for the first client. The jobs model has an attribute for client_id, and I know I can probably just manually fill the attribute, but there has to be some ruby convention to easily accomplish this.

Job.create(:client_id => 1, :subject => "Test", :description => "This is a test")

I can easily put that in my code, but I feel like ruby has a better way to do this. Here is the way my models are setup

class Job < ActiveRecord::Base
  attr_accessible :actual_time, :assigned_at, :client_id, :completed_at, :estimated_time, :location, :responded_at, :runner_id, :status, :subject, :description
  belongs_to :client
end

class Client < User
    has_many :jobs
end

class User < ActiveRecord::Base
  attr_accessible :name, :cell, :email, :pref

end
user2158382
  • 4,430
  • 12
  • 55
  • 97
  • `client = Client.new; Job.create(:client => client, :subject => "Test", :description => "This is a test")` – tessi Apr 29 '13 at 19:47

5 Answers5

19

Just call create on the jobs collection of the client:

c = Client.find(1)
c.jobs.create(:subject => "Test", :description => "This is a test")
alf
  • 18,372
  • 10
  • 61
  • 92
  • 1
    Bad, would raise an ActiveRecord::RecordNotFound if there is no entry with id=1 .... use `Client.find(:first)` or `Client.first` – MrYoshiji Apr 29 '13 at 19:50
  • 3
    @MrYoshiji raising an exception is usually the expected behavior since in rails `RecordNotFound` exceptions are translated into 404 requests in the exceptions app. – alf Apr 29 '13 at 19:51
5

You can pass the object as argument to create the job:

client = Client.create
job = Job.create(client_id: client.id, subject: 'Test', description: 'blabla')

The create method will raise an error if the object is not valid to save (if you set validations like mandatory name, etc).

MrYoshiji
  • 54,334
  • 13
  • 124
  • 117
4

You can use create_job in this way:

client = Client.create
job = client.create_job!(subject: 'Test', description: 'blabla')

When you declare a belongs_to association, the declaring class automatically gains five methods related to the association:

association
association=(associate)
build_association(attributes = {})
create_association(attributes = {})
create_association!(attributes = {})

In all of these methods, association is replaced with the symbol passed as the first argument to belongs_to.

more: http://guides.rubyonrails.org/association_basics.html#belongs-to-association-reference

  • This would work if the association was belongs_to instead of has_many. Good to know, but it doesn't address the issue. – mlabarca May 15 '18 at 16:49
3

Pass the object itself as an argument, instead of passing its ID. That is, instead of passing :client_id => 1 or :client_id => client.id, pass :client => client.

client = Client.find(1)
Job.create(:client => client, :subject => "Test", :description => "This is a test")
Rory O'Kane
  • 29,210
  • 11
  • 96
  • 131
-4

For creating new instances you could use factories. For this you could simply use FactoryGirl https://github.com/thoughtbot/factory_girl

So after you have defined your factory soewhat like this:

FactoryGirl.define do factory :job do client FactoryGirl.create(:client) subject 'Test' description 'This is a Test'

You could then call FactoryGirl.create(:job) to generate a new job like that. You could also call FactoryGirl.build(:job, client: aClientYouInstantiatedBefore, subject: 'AnotherTest') and also overwrite any other attributes

Factores are good if you want to create many objects, that are similar in a certain way.

MentholBonbon
  • 745
  • 4
  • 10
  • 1
    Nowhere in his question, he mentioned that he wants to do it for specs. – kiddorails Apr 29 '13 at 19:50
  • you can use factories anywhere not only in specs or tests – MentholBonbon Apr 29 '13 at 20:01
  • 7
    if you're using factory girl for development you're doing it wrong. – Senjai May 30 '14 at 18:21
  • 1
    @MentholBonbon you're right that `Factories are good if you want to create many objects, that are similar in a certain way`...that's the design pattern definition. But FactoryGirl, despite the name, is for testing. – Dty Sep 01 '15 at 20:27
  • You could use it in `group: development`, but only for creating stuff in the console quickly. It should never be in the gemfile's production group, or comitted in any part of your models/controllers/views. – mlabarca May 15 '18 at 16:52