Rails编辑表单正在每个表单提交上创建一个新元素,而不是更新所选表单

问题描述 投票:0回答:2

我已经在edit.html.erb中创建了一个编辑表单,但是每次我提交它都会创建一个新元素。我已经尝试检查路线,相关的控制器动作,模型中的验证等。在这里我无法弄清楚自己在做什么错。我以为可能需要在表格的开头放置<form action="/books/<%= @book.id %>" method="post">,或者将方法更改为“补丁”,但是这两种方法都不能解决问题。我也尝试注释掉验证,但这也无济于事。只有一个模型。谢谢,如果您发现我做错了,请告诉我!

这是我在不同文件中所拥有的:

routes.rb:

Rails.application.routes.draw do
  resources :books
  root 'books#index'
end

book.rb:

class Book < ApplicationRecord
  validates :title, :author, :total_pages, :dewey, :status, presence: true
end

books_controller.rb:

class BooksController < ApplicationController
  before_action :find_book, only: [:show, :edit, :update, :destroy]

  def index
    @books = Book.all
  end

  def show
  end

  def new
    @book = Book.new
  end

  def create
    @book = Book.create(book_params)

    if @book.status == 'Incomplete'
      @book.pages_read = @book.total_pages / 2
    elsif @book.status = 'Unread'
      @book.pages_read = 0
    else
      @book.pages_read = @book.total_pages
    end

    # Save by category
    # Must save as a string to maintain leading zeros
    if @book.dewey.to_s.split('').map { |digit| digit.to_i }.first == 0
      @book.category = "Computer Science, Information & General Works"
    elsif @book.dewey.to_s.split('').map { |digit| digit.to_i }.first == 1
      @book.category = "Philosophy & Psychology"
    elsif @book.dewey.to_s.split('').map { |digit| digit.to_i }.first == 2
      @book.category = "Religion"
    elsif @book.dewey.to_s.split('').map { |digit| digit.to_i }.first == 3
      @book.category = "Social Science"
    elsif @book.dewey.to_s.split('').map { |digit| digit.to_i }.first == 4
      @book.category = "Language"
    elsif @book.dewey.to_s.split('').map { |digit| digit.to_i }.first == 5
      @book.category = "Pure Science"
    elsif @book.dewey.to_s.split('').map { |digit| digit.to_i }.first == 6
      @book.category = "Applied Science"
    elsif @book.dewey.to_s.split('').map { |digit| digit.to_i }.first == 7
      @book.category = "Arts & Recreation"
    elsif @book.dewey.to_s.split('').map { |digit| digit.to_i }.first == 8
      @book.category = "Literature"
    elsif @book.dewey.to_s.split('').map { |digit| digit.to_i }.first == 9
      @book.category = "History & Geography"
    end

    if @book.valid?
      @book.save
      flash[:message] = "Book saved"
      redirect_to @book
    else
      render :new
    end
  end

  def edit
  end

  def update
    if @book.status == 'Incomplete'
      @book.pages_read = @book.total_pages / 2
    elsif @book.status = 'Unread'
      @book.pages_read = 0
    else
      @book.pages_read = @book.total_pages
    end

    # Save by category
    # Must save as a string to maintain leading zeros
    if @book.dewey.to_s.split('').map { |digit| digit.to_i }.first == 0
      @book.category = "Computer Science, Information & General Works"
    elsif @book.dewey.to_s.split('').map { |digit| digit.to_i }.first == 1
      @book.category = "Philosophy & Psychology"
    elsif @book.dewey.to_s.split('').map { |digit| digit.to_i }.first == 2
      @book.category = "Religion"
    elsif @book.dewey.to_s.split('').map { |digit| digit.to_i }.first == 3
      @book.category = "Social Science"
    elsif @book.dewey.to_s.split('').map { |digit| digit.to_i }.first == 4
      @book.category = "Language"
    elsif @book.dewey.to_s.split('').map { |digit| digit.to_i }.first == 5
      @book.category = "Pure Science"
    elsif @book.dewey.to_s.split('').map { |digit| digit.to_i }.first == 6
      @book.category = "Applied Science"
    elsif @book.dewey.to_s.split('').map { |digit| digit.to_i }.first == 7
      @book.category = "Arts & Recreation"
    elsif @book.dewey.to_s.split('').map { |digit| digit.to_i }.first == 8
      @book.category = "Literature"
    elsif @book.dewey.to_s.split('').map { |digit| digit.to_i }.first == 9
      @book.category = "History & Geography"
    end

    @book.update(book_params)

    if @book.update(book_params)
      flash[:message] = "Successfully updated."
      redirect_to @book
    else
      flash[:errors] = @book.errors.full_messages
      render :edit
    end
  end

  def destroy
    @book.destroy
    flash[:message] = "Book deleted."
    redirect_to books_path
  end

  private

  def book_params
    params.require(:book).permit(:title, :author, :total_pages, :pages_read, :dewey, :category, :status)
  end

  def find_book
    @book = Book.find(params[:id])
  end
end

edit.html.erb:

<form action="/books" method="post">
  <%=hidden_field_tag :authenticity_token, form_authenticity_token %>
  <div class="container">
    <h2 id="form-h2">Editing <%= @book.title %> by <%= @book.author %></h2>
    <div class="form-group row">
      <div class="col-sm-6">
        <input type="text" class="form-control" id="title" placeholder="Title" name="book[title]" value="<%= @book.title %>">
      </div>
      <div class="col-sm-6">
        <input type="text" class="form-control" id="author" placeholder="Author" name="book[author]" value="<%= @book.author %>">
      </div>
    </div>
    <div class="form-group row">
      <div class="col-sm-6">
        <input type="text" class="form-control" id="total_pages" placeholder="Number of pages" name="book[total_pages]" value="<%= @book.total_pages %>">
      </div>
      <div class="col-sm-6">
        <input type="text" class="form-control" id="dewey" placeholder="Dewey Decimal number" name="book[dewey]" value="<%= @book.dewey %>">
      </div>
    </div>
    <p id="form-question">Have you finished this book?</p>
    <div id="radios">
      <div class="custom-control custom-radio">
        <input type="radio" id="customRadio1" name="book[status]" value="Read" class="custom-control-input">
        <label class="custom-control-label"for="customRadio1">Yes!</label>
      </div>
      <div class="custom-control custom-radio">
        <input type="radio" id="customRadio2" name="book[status]" value="Incomplete" class="custom-control-input">
        <label class="custom-control-label"for="customRadio2">I'm still reading it</label>
      </div>
      <div class="custom-control custom-radio">
        <input type="radio" id="customRadio3" name="book[status]" value="Unread" class="custom-control-input">
        <label class="custom-control-label" for="customRadio3">I haven't started it yet</label>
      </div>
    </div>
    <div class="form-group row">
      <div class="col-sm-4">
        <button type="submit" id="add-button" class="btn btn-primary">Done</button>
      </div>
    </div>
  </div>
</form>
ruby-on-rails ruby forms ruby-on-rails-5
2个回答
1
投票

我亲自尝试过,我认为使用专用的表单帮助程序会更好:

<%= form_for @book do |f| %>
  <%= f.text_field :title %>
  <%= f.submit %>
  <!-- all the rest of your fields --> 
<% end %>

这是生成的内容:

<form class="edit_book" id="edit_book_4" action="/books/4" accept-charset="UTF-8" method="post">
  <input name="utf8" type="hidden" value="✓">
  <input type="hidden" name="_method" value="patch">
  <input type="hidden" name="authenticity_token" value="oyzBuqICn/+p8IENt1Dh02UOBzNyCxQ707JwcZdz/BnxocRL4wCzb18Q26DAoDqCFAuqWExII4K1ENGENEPWFA==">
  <input type="text" value="new" name="book[title]" id="book_title">
  <input type="submit" name="commit" value="Update Book" data-disable-with="Update Book">
</form>

请注意此处使用方法patch的额外隐藏字段。

唯一的method属性不理解patchput,您只能在其中使用getposthttps://www.w3schools.com/tags/att_form_method.asp

只有设置了特殊的_method参数,您才能正确路由到update方法。

我不确定您为什么决定努力按照自己的方式编写html表单,但是如果您要继续-保持框架的最新状态将遇到很大的问题。想象一下,从现在开始,Rails团队决定该字段不是_method,而是__method。采用“ canonical”方式-您甚至不会注意到。按照您的方式进行-您将拥有所有要更新的表格。


0
投票

要更新记录,请使用PATCH /books/:id

<%= form_with(model: @book) do |form|>
  <div class="container">
    <h2 id="form-h2">Editing <%= @book.title %> by <%= @book.author %></h2>
    <div class="form-group row">
      <div class="col-sm-6">
        <%= f.label :title %>
        <%= f.text_field :title %>
      </div>
    </div>
    # ...
  </div>
<% end %>

form_with(model: @book)足够聪明,可以根据模型是否已保存到数据库来设置操作和方法。它还负责创建真实性令牌和Rails用来伪造PUT,PATCH和DELETE请求的特殊_method输入。

这使您可以在视图之间共享表单代码。使用form helpers创建带有数据绑定的输入。

如果您手动完成所有操作,则使用框架确实毫无用处-尤其是由配置约定驱动的rails,这使得它如此高效。

© www.soinside.com 2019 - 2024. All rights reserved.