Форма редактирования Rails создает новый элемент при каждой отправке формы вместо обновления выбранного - PullRequest
0 голосов
/ 07 января 2020

Я создал форму редактирования в редактировании. html .erb, но он создает новый элемент каждый раз, когда я отправляю его. Я попытался проверить маршруты, оба соответствующих действия контроллера, проверки в модели и т. Д. c. Я не могу понять, что я делаю здесь не так. Я подумал, что, возможно, мне нужно поставить <form action="/books/<%= @book.id %>" method="post"> в начале формы, или, может быть, изменить метод на «патч», но ни одна из этих комбинаций не решит проблему. Я также пытался закомментировать проверки, но это тоже не помогает. Там только одна модель. Спасибо и, пожалуйста, дайте мне знать, если вы видите, что я делаю неправильно!

Вот что у меня есть в разных файлах:

rout.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>

Ответы [ 2 ]

2 голосов
/ 08 января 2020

Я попробовал это сам, и я думаю, что вам было бы намного лучше, если бы вы использовали выделенных помощников по формам:

<%= 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 не понимает patch или put, в нем можно использовать только get и post (https://www.w3schools.com/tags/att_form_method.asp)

Только с этим специальным набором параметров _method вы получите правильную маршрутизацию к методу update.

Я не уверен, почему вы решили go трудный путь и составить формы html самостоятельно, но если вы хотите продолжить - у вас будут огромные проблемы с сохранением фреймворка своевременно. Представьте, что команда рельсов решает, что это поле теперь не _method, а __method. Идти по « каноническому » пути - вы даже не заметите. Идя своим путем - вы будете иметь все свои формы для обновления.

1 голос
/ 08 января 2020

Для обновления записи вы используете PATCH /books/:id.

# Use form_for if your Rails version is older than 5.1
<%= 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) достаточно умен, чтобы установить действие и метод в зависимости от того, была ли модель сохранена в базе данных. Он также заботится о создании токена подлинности и специального ввода _method, который Rails использует для фальшивых запросов PUT, PATCH и DELETE .

. Это позволяет вам совместно использовать код формы между вашими представлениями. , Используйте помощники по формам для создания входных данных с привязками данных.

Если вы делаете все вручную, это действительно делает бессмысленным использование фреймворка - особенно рельсов, что обусловлено соглашением о конфигурации, что делает его таким продуктивным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...