I am trying to make a simple app for submitting goals of users, who can then mark the goals as completed. I can complete the "new" action fine, but when I'm trying to "edit," the params include the ID of the user instead of the ID of the goal.
For my form partial, I'm using a simple form_with:
> <%= form_with(model: [@user, @goal]) do |f| %>
> <%= f.label :goal_title, "Title" %>
> <%= f.text_field :goal_title %>
> <%= f.label :description, "Description" %>
> <%= f.text_area :description %>
> <%= f.select(:public, [['Public', true], ['Private', false]]) %>
> <%= f.select(:completed, [['Completed', true], ['Not Completed', false]]) %>
> <%= f.submit "Submit" %>
> <% end %>
My controller is as follows:
class GoalsController < ApplicationController
def index
@goals = current_user.goals
render :index
end
def new
@goal = Goal.new(user_id: current_user.id)
@user = current_user
render :new
end
def create
@goal = current_user.goals.new(goal_params)
if @goal.save
redirect_to user_goals_path
flash[:notice] = "Goal saved"
else
flash.now[:errors] = @goal.errors.full_messages
render :new
end
end
def update
@goal = Goal.find_by(id: params[:id])
if @goal.update_attributes(goal_params)
redirect_to user_goals_path
flash[:notice] = "Goal updated"
else
flash.now[:errors] = @goal.errors.full_messages
render :edit
end
end
def edit
@goal = Goal.find_by(id: params[:id])
@user = current_user
render :edit
end
def homepage
@goals = Goal.all
render :index
end
private
def goal_params
params.require(:goal).permit(:goal_title, :description, :completed, :public)
end
end
And my current routes are:
Prefix Verb URI Pattern Controller#Action
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
user_password PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
POST /users/password(.:format) devise/passwords#create
cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel
new_user_registration GET /users/sign_up(.:format) devise/registrations#new
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
user_registration PATCH /users(.:format) devise/registrations#update
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
POST /users(.:format) devise/registrations#create
user_goals GET /user/goals(.:format) goals#index
POST /user/goals(.:format) goals#create
new_user_goal GET /user/goals/new(.:format) goals#new
edit_user_goal GET /user/goals/:id/edit(.:format) goals#edit
user_goal PATCH /user/goals/:id(.:format) goals#update
PUT /user/goals/:id(.:format) goals#update
DELETE /user/goals/:id(.:format) goals#destroy
new_user GET /user/new(.:format) users#new
edit_user GET /user/edit(.:format) users#edit
user GET /user(.:format) users#show
PATCH /user(.:format) users#update
PUT /user(.:format) users#update
DELETE /user(.:format) users#destroy
POST /user(.:format) users#create
goals GET /goals(.:format) goals#homepage
root GET / goals#homepage
The params hash in the "edit" show fine: <ActionController::Parameters {"controller"=>"goals", "action"=>"edit", "id"=>"197"} permitted: false>
but the params for "update" show <ActionController::Parameters {"_method"=>"patch", "goal"=>{"goal_title"=>"Updated goal", "description"=>"Updated description", "public"=>"true", "completed"=>"true"}, "commit"=>"Submit", "controller"=>"goals", "action"=>"update", "id"=>"379"} permitted: false>
. The ID should be 197 (goal ID) not 379 (user ID).
Any suggestions? Thanks.
If you look at your routes again:
user_goals GET /user/goals(.:format) goals#index
POST /user/goals(.:format) goals#create
new_user_goal GET /user/goals/new(.:format) goals#new
edit_user_goal GET /user/goals/:id/edit(.:format) goals#edit
user_goal PATCH /user/goals/:id(.:format) goals#update
PUT /user/goals/:id(.:format) goals#update
DELETE /user/goals/:id(.:format)
Goal is not nested inside user resource, instead user here acts as namespace, therefore when you call form_with(model: [@user, @goal])
Rails will pick user.id
as id
params.
Solution:
If you want it to be a nested resource, you need to change your routes config in config/routes.rb
to something like this.
resources :users do
resources :goals
end
If you don't need nested resource, just change form_with(model: [@user, @goal])
to form_with(model: @goal)