2

I am building a To Do application in an attempt to get fluent with Rails. There are four levels of hierarchy in my app.

  1. User
  2. Goals (multiple goals per user)
  3. Tasks (multiple tasks per goal)
  4. Subtasks (multiple subtasks per task)

I have a working front end form for each of these that utilizes nested resources. My routes.rb has something like this

 resources :goal do
  resources :task do
    resources :subtask
  end
 end

What I would like to do now is that have all these forms right in one of the views of the user controller.

This the form that I have attempted to create :

<%= form_for @task, url: {controller: 'task', action: 'create'} do |f| %>

 <%= f.label :description %>

 <%= f.text_field :description %>

 <%= f.submit "Add Goal", class: "btn" %>

<% end %>

But I end up getting this error

No route matches {:action=>"create", :controller=>"task", :id=>"1"}

The :id=>1 corresponds to the user page I am on (http://localhost:3000/user/1)

What I understand is that there is that nowhere have I provided the goal_id for which this step is intended. No idea how to implement this.

Another thing that I have noticed is that a response to rake routes shows a lot of URI paths but nothing for POST method. It does not allow me to use a path from there in the url: in form_for because it does not match the POST method.

So my questions are :

  1. How to route a form_for that when you have nested resources?
  2. How to provide the ID of the parent resource while using form_for so that my create action is correctly routed?
3
  • probably this would give you some idea: stackoverflow.com/questions/2034700/… Commented Sep 16, 2016 at 8:54
  • Do a rake route and check the create task route. The user id is probably not indicated as :id. Commented Sep 16, 2016 at 9:03
  • no I have /goal/:goal_id/task as the create task route. Yes there is no :id in this route, I still need to provide the :goal_id somewhere and I dont know how to do that (as I mentioned in the question). Commented Sep 16, 2016 at 14:46

1 Answer 1

3

It is typically bad practice to nest routes beyond two levels deep. I would change your routes to:

  resources :goal do
    resources :task 
  end

and

  resources :task do
      resources :subtask
  end

Now if you run "bundle exec rake routes" in the command line you will see all of the nested routes and their corresponding helpers. Your current issue lies with the form_for method. You need to add the resource its nested with which in this case should be:

<%= form_for [@goal,@task] do |f| %>
    blah blah
<% end %>

Lastly, @goal is also still undefined so you'll need to define it in your 'new' action in the tasks controller. This is normally done by passing the id of the goal your task will be associated with via the params hash and the "link_to" used to get to the 'new' form. Then in the new action in your tasks controller:

@goal = Goal.find(params[:goal_id]) #The parameter can be named anything
@task = Task.new

Then in your 'create' action you should have the association made:

@task = Goal.tasks.new(task_params)
if @task.save
   flash[:success] = "Woot" 
   redirect_to somewhere_awesome_path
else
  whatever
end
Sign up to request clarification or add additional context in comments.

3 Comments

Using form_for [@goal,@task]gives me the error undefined method goal_tasks_path for #<#<Class:..... What I really have trouble grasping is how the goal id is passed into the form via the param has and the link_to as you suggested. Also, this form is not in a view associated with either the task controller or the goal controller, its actually in show.html.erb associated with the user controller. How would the form know to look for another controller instead of the user?
thanks for the reply though, its a great answer. Just need a little bit more of your help :)
No problem. You want to define the '@goal' and '@task' inside the action that is connected to displaying the form so in this case you would define them in your User controller inside the Show action. You can then also define the path the form will submit to as you had with the "url: {controller: 'task', action: 'create'}" part. As for passing the goal_id you can add it as a hidden_field inside the form with a preset value. For example <%= f.hidden_field :goal, value: 'whatever value' %>

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.