tfantina
tfantina

Reputation: 805

Rails create multiple records based on user input

I have a projects app that allows all Users on a team to create Tasks, I'd like a User to be able to add users to a Task (for example if multiple people were in a meeting). Essentially the new task form would have all the usernames of those on the team and the user could check a box by each name for anyone else who participated in the task.

Initially, I thought the best way to do this might be a has_many through: relationship where I had:

Tasks:

class Task < ApplicationRecord
    has_many :user_tasks
    has_many :users, through: :user_tasks

Users:

class User < ApplicationRecord

 has_many :user_tasks
 has_many :tasks, through: :user_tasks

And User_Tasks:

class UserTask < ApplicationRecord
  belongs_to :user
  belongs_to :task
end

The idea was that when a new task is created any user_ids tagged in the task would create new entries in User_Tasks. But I am not 100% sure how to do that in the Task create action and I'm starting to wonder if this is over complicating things?

Is there a simpler way to do this? If not what is the best way to structure a create action around this has_many through: association?

Upvotes: 0

Views: 1483

Answers (2)

max
max

Reputation: 102026

Its actually much simpler than you think. ActiveRecord creates an _ids setter and getter for has_many associations. The setter will automatically add/delete records in the join table. For example:

@task = Task.create!(user_ids: [1,2,3])
@task.user_ids # => [1,2,3]

Would create a task and three rows in the join table.

You can use this in forms with the collection helpers:

<%= form_for(@task) do |f| %>
  ...
  <%= f.collection_checkboxes(:user_ids, User.all, :id, :name) %>
  ...
<% end %>

Here I am just guessing that your users have a name attribute (used for the text of the checkbox). You can use whatever collection you want instead of User.all.

To whitelist the user_ids param (which is an array) use a hash option with an array as the value:

def task_params
  params.require(:task).permit(:foo, :bar, user_ids: [])
end

This permits an array of permitted scalar types.

Upvotes: 1

sloneorzeszki
sloneorzeszki

Reputation: 1524

I think you're pretty much spot on with your associations. UserTask table is being automatically updated by Rails every time you add an object to the collection (either collection of tasks assigned to user or users assigned to a task). So with your current setup you should be able to do:

user = User.first 
task = Task.first
user.tasks << task

which would also automatically create a record in UserTask table.

That way you should be able to pull off in Task create action something like this:

task.users << User.find([1,2])

Upvotes: 1

Related Questions