Reputation: 804
I'm having trouble creating a record with a has_many through: relationship in Rails. I have a User model, a Task model and a Timer Model. The idea is that a User has_many :tasks
and also has_many :timers through: :tasks
Tasks also have many timers. The idea is that a user can create as many tasks as they want and time themselves each day doing a specific task to track progress over time.
User.rb
class User < ApplicationRecord
has_many :tasks
has_many :timers, through: :tasks
end
Task.rb
class Task < ApplicationRecord
validates :user_id, presence: true
belongs_to :user
has_many :timers
end
Timer.rb
class Timer < ApplicationRecord
belongs_to :task
end
The objective is that the user can see their tasks and start and stop a timer next to each task. The timer is simple enough, it just has a date created and date modified that will track how long it ran.
However, in the timers_controller I'm not really sure how to create a timer:
class TimersController < ApplicationController
def new
@timer = Timer.new
end
def create
@timer = current_user.build(timer_params)
end
private
def timer_params
params.require(:timer).permit(:start_time)
end
end
I've tried changing the structure of the create action as well as the params but so far nothing has worked.
For some additional context here is the tasks/index.html.erb
<% @tasks.each do |t| %>
<%= t.title %>
<%= form_for(@user.timers.build) do |f| %>
<%= f.submit "Start", class: "btn btn-primary" %>
<% end %>
<br />
<% end %>
This is the Timer Migration:
class CreateTimers < ActiveRecord::Migration[5.1]
def change
create_table :timers do |t|
t.integer :user_id
t.integer :task_id
t.datetime :start_time
t.datetime :end_time
t.timestamps
end
add_index :timers, :user_id
add_index :timers, :task_id
end
end
Tasks migration:
class CreateTasks < ActiveRecord::Migration[5.1]
def change
create_table :tasks do |t|
t.string :title
t.text :description
t.timestamps
end
end
end
Upvotes: 0
Views: 74
Reputation: 3005
This is not a complete answer but some ideas.
Joe Marion's answer can be right, if a task has only one timer. This seems reasonable, but it's not what you wrote (Tasks also have many timers). So here you have another option.
When you create the timer, it should be associated to a task (not directly to the user). And of course you need to know in advance which task the timer belongs to. The task_id should be a parameter in the form.
So the build command should be something like this
def create
task = current_user.tasks.find_by(id: params[:task_id])
if task
@timer = task.timers.build(timer_params)
if @timer.save
# ....
else
# .....
else
# Error, task not found. Timer cannot be created
# Whatever you want to do in this case ...
end
end
In the view, your forms should be associated with tasks and should include the task_id to be used in the create action.
<% @tasks.each do |t| %>
<%= t.title %>
<%= form_for(t.timers.build) do |f| %>
<!-- where is the start_time field? -->
<%= f.hidden_field :task_id %>
<%= f.submit "Start", class: "btn btn-primary" %>
<% end %>
<br />
<% end %>
Upvotes: 1
Reputation: 406
If you want to track how long each task takes you could just add a timer field to a user_tasks table.
User.rb
class User < ApplicationRecord
has_many :user_tasks
has_many :tasks, through: :user_tasks
end
Task.rb
class Task < ApplicationRecord
has_many :user_tasks
has_many :users, through: :user_tasks
end
Timer.rb
class UserTasks < ApplicationRecord
belongs_to :task
belongs_to :user
end
The UserTasks is a join table that represents each individual task by the user. So if you added a time_to_complete field to the UserTasks table it would show the time for each task per user.
Upvotes: 0