Вложенные формы Rails 4 link_to edit не работают в цикле

У меня есть вложенные маршруты/модели/формы в рельсах. На моей индексной странице я перечисляю todo_lists с todo_items внизу. Я хочу, чтобы у меня была возможность щелкнуть заголовок моего списка задач, а затем он перенаправит меня на страницу редактирования. Я исследую полиморфные маршруты и вложенные маршруты.

ОБНОВЛЕНИЕ

Это было моим исправлением, чтобы он не создавал фиктивный список задач.

<%  @current_todo_lists.each do |list| %>
    <% if list.id %>
        <div class="panel">
            <p><strong><%= link_to list.title ,edit_todo_list_path(list)%></strong></p>
            <% list.todo_items.each do |todo_item| %>
                <p><%= todo_item.description %></p>
            <% end %>
        </div>
    <% end %>
<% end %>

ссылка на github

Редактирование вложенной формы Link_to rails

polymorphic_path не генерирует правильный путь Я провел много исследований в поисках to cocoon, направляющие рельсы на полиморфных маршрутах и ​​несколько других ссылок stackoverflow.

Мне не удалось выполнить ни одну из этих работ.

Вот индексная страница, где перечислены все мои todo_lists с todo_items. Он проходит через цикл, чтобы перечислить каждый список задач с соответствующими элементами, созданными с его помощью.

Обновление:

Я уже пробовал <%= link_to list.title, edit_todo_list_path(list) %>и <%= link_to list.title, edit_todo_list_path(@list) %>. Сообщение об ошибке, которое я получаю:

ActionController::UrlGenerationError at /todo_lists No route matches {:action=>"edit", :controller=>"todo_lists", :id=>nil} missing required keys: [:id] Эта же конфигурация с @todo_list дает ту же ошибку. По сути, он не может найти список задач с идентификатором.

В консоли действительно дает мне результат. Так что я что-то упускаю.

>> t = TodoList.find(1)
=> #<TodoList id: 1, title: "First todo List with a modal", created_at: "2014-09-09 23:02:27", updated_at: "2014-09-09 23:02:27", user_id: 1>
>>

Обновление 2: здесь возникает ошибка в моем контроллере списка дел. Без id не находит.

def set_todo_list
@todo_list = TodoList.find(params[:id])
end


<% @todo_lists.each do |list| %> 
    <p><strong><%= link_to list.title, edit_polymorphic_path(@todo_list) %></strong></p>
    <% list.todo_items.each do |todo_item| %>
        <p><%= todo_item.description %></p>
    <% end %>
<% end %>

До сих пор <p><strong><%= link_to list.title, edit_polymorphic_path(@todo_list) % параметров были @todo_list(s), @todo_lists(s), todo_items и так далее.

Модели:

class TodoList < ActiveRecord::Base
    has_many :todo_items, dependent: :destroy
    accepts_nested_attributes_for :todo_items, allow_destroy: true
    validates_presence_of :title
end

class TodoItem < ActiveRecord::Base
    belongs_to :todo_list
end

Контроллеры:

Class TodoListsController < ApplicationController
  before_filter :authenticate_user!
  before_filter except: [:index]
  before_action :set_todo_list, only: [:show, :edit, :update, :destroy]

  # GET /todo_lists
  # GET /todo_lists.json
  def index
    #@todo_lists = TodoList.all
    #find current user todo lists/items
    @todo_lists = current_user.todo_lists
    @todo_items = current_user.todo_items
    #create a new user todo list
    @todo_list = current_user.todo_lists.new
    # builder for todo list _form
    3.times{ @todo_list.todo_items.build }
  end

  # GET /todo_lists/1
  # GET /todo_lists/1.json
  def show
  end

  # # GET /todo_lists/new
  def new
    @todo_list = current_user.todo_lists.new
    3.times{ @todo_list.todo_items.build }
  end

  # GET /todo_lists/1/edit
  def edit
    #@todo_list = TodoList.find(todo_list_params)
    @todo_list = TodoList.find(params[:id])
  end

  # POST /todo_lists
  # POST /todo_lists.json
  def create
    #@todo_list = TodoList.new(todo_list_params)
    @todo_list = current_user.todo_lists.new(todo_list_params)
    respond_to do |format|
      if @todo_list.save
        format.html { redirect_to @todo_list, notice: 'Todo list was successfully created.' }
        format.json { render :show, status: :created, location: @todo_list }
      else
        format.html { render :new }
        format.json { render json: @todo_list.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /todo_lists/1
  # PATCH/PUT /todo_lists/1.json
  def update
    @todo_list = TodoList.find(params[:id])
    respond_to do |format|
      if @todo_list.update(todo_list_params)
        format.html { redirect_to @todo_list, notice: 'Todo list was successfully updated.' }
        format.json { render :show, status: :ok, location: @todo_list }
      else
        format.html { render :edit }
        format.json { render json: @todo_list.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /todo_lists/1
  # DELETE /todo_lists/1.json
  def destroy
    #@todo_list.TodoList.find(params[:id])
    @todo_list.destroy
    respond_to do |format|
      format.html { redirect_to todo_lists_url, notice: 'Todo list was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    def owns_todolist
      if current_user != TodoList.find(params[:id]).user
        redirect_to todo_lists_path, error: "You can't do that!"
      end
    end
    # Use callbacks to share common setup or constraints between actions.
    def set_todo_list
      @todo_list = TodoList.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def todo_list_params
      params.require(:todo_list).permit(:title, todo_items_attributes: [:description, :_destroy])
    end
end



class TodoItemsController < ApplicationController
  before_action :set_todo_item, only: [:show, :edit, :update, :destroy]
  before_action :set_todo_list

  # GET /todo_items
  # GET /todo_items.json
  def index
    @todo_items = TodoItem.all
  end

  # GET /todo_items/1
  # GET /todo_items/1.json
  def show
    @todo_item = TodoItem.find(params[:id])
  end

  # GET /todo_items/new
  def new
    @todo_item = @todo_list.todo_items.build
  end

  # GET /todo_items/1/edit
  def edit
    @todo_item = TodoItem.find(params[:id])
  end

  # POST /todo_items
  # POST /todo_items.json
  def create
    @todo_item = @todo_list.todo_items.build(todo_item_params)

    respond_to do |format|
      if @todo_item.save
        format.html { redirect_to [@todo_list,@todo_item], notice: 'Todo item was successfully created.' }
        format.json { render :show, status: :created, location: @todo_item }
      else
        format.html { render :new }
        format.json { render json: @todo_item.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /todo_items/1
  # PATCH/PUT /todo_items/1.json
  def update
    @todo_item = TodoItem.find(params[:id])
    respond_to do |format|
      if @todo_item.update(todo_item_params)
        format.html { redirect_to @todo_item, notice: 'Todo item was successfully updated.' }
        format.json { render :show, status: :ok, location: @todo_item }
      else
        format.html { render :edit }
        format.json { render json: @todo_item.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /todo_items/1
  # DELETE /todo_items/1.json
  def destroy
    @todo_item = TodoItem.find(params[:id])
    @todo_item.destroy
    respond_to do |format|
      format.html { redirect_to todo_list_todo_items_url, notice: 'Todo item was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_todo_item
      @todo_item = TodoItem.find(params[:id])
    end

    def set_todo_list
      @todo_list = TodoList.find(params[:todo_list_id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def todo_item_params
      params.require(:todo_item).permit(:description, :text, :todo_list_id)
    end
end

и, наконец, форма. Прямо сейчас он позволяет добавлять todo_list и несколько todo_items просто для практики. Я планирую использовать Ajax для динамического создания позже. И иметь другую форму для редактирования.

<%= form_for(@todo_list) do |f| %>
  <% if @todo_list.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@todo_list.errors.count, "error") %> prohibited this todo_list from being saved:</h2>

      <ul>
      <% @todo_list.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>
  <div class="field">
    <%= f.label :title %><br>
    <%= f.text_field :title %>
  </div>
  <div>
    <%= f.fields_for :todo_items do |builder| %>
      <%= builder.label :description, "Items" %>
      <%= builder.text_field :description %>
      <%= builder.check_box '_destroy' %>
    <% end %>

  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

person T.J.    schedule 10.09.2014    source источник
comment
Почему вы хотите использовать edit_polymorphic_path? Ни TodoList, ни TodoItem не являются полиморфными, просто используйте edit_todo_list_path(list).   -  person max    schedule 10.09.2014
comment
Я попробовал это. Первое, что я сделал. Я отредактировал свой вопрос выше с ошибкой, которую я получаю.   -  person T.J.    schedule 10.09.2014
comment
edit_todo_list_path(идентификатор: @list.id)   -  person Will    schedule 10.09.2014
comment
edit_todo_list_path(list) должно работать. (@list здесь не является переменной). Если это не работает, сообщение об ошибке такое же? (Идентификатор по-прежнему равен нулю? Если это все еще ошибка маршрутизации, но идентификатор не равен нулю, вам может потребоваться добавить путь редактирования в файл route.rb). Кроме того, полиморфизм для отношений данных отличается от того, который у вас есть здесь. Это не похоже на правильный инструмент для работы.   -  person Sasha    schedule 10.09.2014
comment
Чтобы ответить на ваш вопрос: ActionController::UrlGenerationError in TodoLists#index Нет, это не работает. No route matches {:action=>"edit", :controller=>"todo_lists", :id=>nil} missing required keys: [:id]   -  person T.J.    schedule 10.09.2014


Ответы (2)


Я думаю, что проблема на самом деле немного сложнее, потому что edit_todo_list_path(list), похоже, выдает ту же ошибку.

Происходит то, что переменная @todo_lists (сначала массив постоянных списков) изменяется при запуске @todo_list = current_user.todo_lists.new. Эта команда на самом деле добавляет новый (не сохраняемый) список в конец массива @todo_lists (мне это кажется ошибочным поведением, но это случалось со мной раньше), так что, когда ваше представление перебирает их, последний не имеет идентификатора, и путь для него не может быть создан.

Решение (я думаю) состоит в том, чтобы сделать эту переменную после того, как вы использовали переменную @todo_lists.

Уберите @todo_list из контроллера, и там, где вы его используете в представлении, вместо этого сделайте current_user.todo_lists.build. Это должно создать экземпляр нового списка без изменения переменной @todo_lists.

person Sasha    schedule 10.09.2014

Вы пытаетесь создать ссылку на ресурс, который еще не сохранен:

#create a new user todo list
@todo_list = current_user.todo_lists.new

Поскольку вы никогда не вызываете @todo_list.save, запись не имеет идентификатора и не может быть перенаправлена.

Я думаю, что вы пытаетесь сделать следующее:

<% @todo_lists.each do |list| %> 
  <p><strong><%= link_to list.title, edit_polymorphic_path(id: list.to_param) #not @todo_list! %></strong></p>
  <% list.todo_items.each do |todo_item| %>
    <p><%= todo_item.description %></p>
  <% end %>
<% end %>

И я бы серьезно подумал о переименовании @todo_list -> @new_todo_list, так как это довольно запутанно.


Обновлять

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

Что вам нужно сделать, так это заставить пользователя создать новый ресурс, отправив форму с запросом AJAX POST на /todo_list, а затем обновить страницу с новым списком (и ссылкой для редактирования).

Сейчас вы создаете новый todo_list, который существует только в памяти сервера до того, как rails закончит обработку запроса.

person max    schedule 10.09.2014
comment
Позвольте мне уточнить. Приведенный выше код будет перечислять каждый список задач с элементами задач. Я даже могу нажать кнопку, чтобы открыть модальное окно, которое создаст новый список дел на той же странице. Как только список будет создан. Я пытаюсь создать ссылку для редактирования, используя заголовок. edit_polymorphic_path(id: list.to_param) Не работает. Я добавил еще одно редактирование выше. - person T.J.; 10.09.2014
comment
Если вы хотите явно установить идентификатор, вы должны сделать path(id: list.id). Я согласен, что путь должен быть edit_todo_path, а идентификатор действительно должен извлекаться автоматически. Я думаю, что проблема заключалась в том, что, как сказал papirtiger, вы передавали неправильный (не сохраняемый, т.е. без идентификатора) объект помощнику пути. - person Sasha; 10.09.2014
comment
Спасибо за помощь всем. Спасибо @papirtiger за предложение переименовать мои переменные. Это привело к некоторому упрощению и очистке моего кода. - person T.J.; 11.09.2014