1

In my Rails app I have Clients and Users. And Users can have many Clients.

The models are setup as so:

class Client < ApplicationRecord
  has_many :client_users, dependent: :destroy
  has_many :users, through: :client_users
end

class User < ApplicationRecord
  has_many :client_users, dependent: :destroy
  has_many :clients, through: :client_users
end

class ClientUser < ApplicationRecord
  belongs_to :user
  belongs_to :client
end

So if I wanted to create a new client that had the first two users associated with it how would I do it?

e.g.

Client.create!(name: 'Client1', client_users: [User.first, User.second])

Trying that gives me the error:

ActiveRecord::AssociationTypeMismatch: ClientUser(#70142396623360) expected, got #<User id: 1,...

I also want to do this for an RSpec test. e.g.

user1 = create(:user)
user2 = create(:user)

client1 = create(:client, client_users: [user1, user2])

How do I create a client with associated users for in both the Rails console and in an RSpec test?

3
  • Try This User.create(name: 'oneuser') User.create(name: 'twouser') @client = Client.create(name: 'Client1') @client.users << User.first @client.users << User.second Commented Sep 27, 2017 at 9:51
  • @VaibhavDhoke So the client has to exist first? I can't create and associate at the same time? Commented Sep 27, 2017 at 9:54
  • This is one way of doing it, maybe that also could be done, but I am not aware of it. still. Please refer this link for more info. Commented Sep 27, 2017 at 9:56

6 Answers 6

2

If you do not want to accept_nested_attributes for anything, as documented here you can also pass block to create.

Client.create!(name: 'Client1') do |client1| 
  client1.users << [User.find(1), User.find(2), User.find(3)]     
end
Sign up to request clarification or add additional context in comments.

Comments

1

Try this. It should work

Client.create!(name: 'Client1').client_users.new([{user_id: User.first},{user_id: User.second}])

1 Comment

@Cameron Try above solution
1

You can do this with the following code:

user1 = create(:user)
user2 = create(:user)

client1 = create(:client, users: [user1, user2])

See ClassMethods/has_many for the documentation

collection=objects

Replaces the collections content by deleting and adding objects as appropriate. If the :through option is true callbacks in the join models are triggered except destroy callbacks, since deletion is direct.

If you are using factory_girl you can add trait :with_users like this:

FactoryGirl.define do
  factory :client do

    trait :with_two_users do
      after(:create) do |client|
        client.users = create_list :user, 2
      end
    end

  end
end

Now you can create a client with users in test like this:

client = create :client, :with_two_users

Comments

0

accepts_nested_attributes_for :users

and do as so:

Client.create!(name: 'Client1', users_attributes: { ........ })

hope this would work for you.

Comments

0

You can make use of after_create callback

class Client < ApplicationRecord
  has_many :client_users, dependent: :destroy
  has_many :users, through: :client_users

  after_create :add_users

  private def add_users
    sef.users << [User.first, User.second]
  end
end

Alternatively, A simpler approach would be

Client.create!(name: 'Client1', user_ids: [User.first.id, User.second.id])

Comments

0

The reason you're getting a mismatch is because you're specifying the client_users association that expects ClientUser instances, but you're passing in User instances:

# this won't work
Client.create!(client_users: [User.first, User.second])

Instead, since you already specified a users association, you can do this:

Client.create!(users: [User.first, User.second])

There's a simpler way to handle this, though: ditch the join model and use a has_and_belongs_to_many relationship. You still need a clients_users join table in the database, but you don't need a ClientUser model. Rails will handle this automatically under the covers.

class Client < ApplicationRecord
  has_and_belongs_to_many :users
end

class User
  has_and_belongs_to_many :clients
end

# Any of these work:
client = Client.new(name: "Kung Fu")
user = client.users.new(name: "Panda")
client.users << User.new(name: "Nemo")
client.save # => this will create two users and a client, and add two records to the `clients_users` join table

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.