I have the three models set up like the below (incomplete for brevity):
class Client < ActiveRecord::Base
has_many :roles
has_many :cases, through: :roles
end
class Role < ActiveRecord::Base
belongs_to :client
belongs_to :case
end
class Case < ActiveRecord::Base
has_many :roles
has_many :clients, through: :roles
accepts_nested_attributes_for :roles, :clients
end
It's a simple has_many through
association. I've set up the models to accept nested attributes for the appropriate associations, and permitted the parameters properly in my controller. I'm sending the below request body JSON to POST /cases
which hits this method:
def create
@case = Case.new(case_params)
if @case.save
render json: @case, root: 'case', status: :created, location: @case, serializer: CaseShowSerializer
else
render json: @case.errors, status: :unprocessable_entity
end
end
And the JSON:
{
"case": {
"state": "CA",
"clients_attributes": [
{
"first_name": "John",
"last_name": "Doe",
"email": "johndoe@gmail.com"
}
]
}
}
The case is created and the nested clients array are also created. Rails automatically creates Role
records for each Client
in the array of JSON. However, it only sets case_id
and client_id
(which associates the two). I ALSO want to set other fields on the Role
model that it creates.
How can this be done?
Edit:
Both answers below (Oct 1 2015, 12:50PM PST) will not work. Using those answer's logic, a client can not have multiple roles (which is needed and explicitly defined in the model).
Example:
The roles CAN NOT nested inside of the case --
{
"case": {
"name": "test",
"roles_attributes": [
{
"type": "Type 1",
"client_attributes": {
"name": "Client 1"
}
},
{
"type": "Type 2",
"client_attributes": {
"name": "Client 1"
}
}
]
}
}
The JSON above will create the SAME client twice. The Client with a name of "Client 1" has two roles, one of the roles type is "Type 1" the other is "Type 2". The snippet above as suggested by the answer would create two clients and two roles. It should create one client (since it's the same client but that client has multiple roles).