Вложенный ресурс Rails, возвращающий неверный идентификатор в хэше параметров

#ruby-on-rails #ruby #controller #devise #nested

#ruby-on-rails #ruby #контроллер #разработать #вложенный

Вопрос:

Я пытаюсь создать простое приложение для отправки целей пользователей, которые затем могут пометить цели как завершенные. Я могу выполнить «новое» действие нормально, но когда я пытаюсь «редактировать», параметры включают идентификатор пользователя вместо идентификатора цели.

Для моей формы partial я использую простую 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 %>
  

Мой контроллер выглядит следующим образом:

 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
  

И мои текущие маршруты:

                        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
  

Хэш параметров в «редактировать» отображается нормально: <ActionController::Parameters {"controller"=>"goals", "action"=>"edit", "id"=>"197"} permitted: false> но отображаются параметры для «обновить» <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> . Идентификатор должен быть 197 (идентификатор цели), а не 379 (идентификатор пользователя).

Есть предложения? Спасибо.

Комментарии:

1. нет необходимости писать user в form_with, просто напишите form_with(модель: @goal), и это решит вашу проблему. Кроме того, вы можете написать маршруты участников, чтобы вам не приходилось писать goal = Goal.find_by(id: params[:id]) в методах редактирования и обновления.

Ответ №1:

Если вы снова посмотрите на свои маршруты:

                    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) 
  

Цель не вложена в пользовательский ресурс, вместо этого пользователь здесь действует как пространство имен, поэтому при вызове form_with(model: [@user, @goal]) Rails будет выбирать user.id как id параметры.

Решение:

  1. Если вы хотите, чтобы это был вложенный ресурс, вам нужно изменить конфигурацию маршрутов в config/routes.rb на что-то вроде этого.

     resources :users do
      resources :goals
    end
      
  2. Если вам не нужен вложенный ресурс, просто измените form_with(model: [@user, @goal]) на form_with(model: @goal)

Комментарии:

1. Я смог сохранить свой уникальный пользовательский ресурс и изменил свой form_with на: <% action_url = @goal.persisted? ? user_goal_path(@goal) : user_goals_path %> <%= form_with(model: @goal, url: "#{action_url}") do |f| %>

2. Отлично, если это соответствует вашим потребностям.