Как добавить комментарии к просмотру? - PullRequest
0 голосов
/ 07 января 2020

Я изучаю Rails и пытаюсь добавить функцию комментария.

У меня возникает ошибка при попытке добавить комментарий: Нет совпадений с маршрутом [POST] "/ advertisements / 1"

Как мне сказать Rails: «Эй, чувак, я хотел бы, чтобы ты go оставил мои комментарии # create function»

#app/views/advertisements/show.html.erb
<% if @current_user %>
    <%= render "comments/form", comment: @comment %>
<% end %>
#app/views/comments/_form.html.erb
<%= form_with(model: comment, local: true) do |form| %>

  <div class="field">
    <%= form.text_area :content %>
  </div>

  <div class="field">
    <%= form.hidden_field :user_id, :value => @current_user.id %>
  </div>

  <div class="field">
    <%= form.hidden_field :advertisement_id, :value => @advertisement.id %>
  </div>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>
#app/controllers/comments_controller.rb
class CommentsController < ApplicationController

  # GET /comments/new
  def new
    @comment = Comment.new
  end

  # POST /comments
  # POST /comments.json
  def create
    @comment = Comment.new(comment_params)

    respond_to do |format|
      if @comment.save
        format.html { redirect_to @comment, notice: 'Comment was successfully created.' }
      else
        format.html { render :new }
      end
    end
  end

  private

    # Never trust parameters from the scary internet, only allow the white list through.
    def comment_params
      params.require(:comment).permit(:content, :user_id, :advertisement_id)
    end
end

HTML форма визуализирована (почему у него есть "/ advtertisements / 1" при вводе действия

<form action="/advertisements/1" accept-charset="UTF-8" method="post">

<input type="hidden" name="authenticity_token" value="pJOwu9LyhQmj4uSYhyeBKD66Zab+kJf9bR1m+eJJ1Fj+kznMl/4rVz69ucPa2gkuOc/yUB8rPLWhpH+6GHWaqQ==" />

  <div class="field">
    <textarea name="content" id="content">
</textarea>
  </div>

  <div class="field">
    <input value="1" type="hidden" name="user_id" id="user_id" />
  </div>

  <div class="field">
    <input value="1" type="hidden" name="advertisement_id" id="advertisement_id" />
  </div>

  <div class="actions">
    <input type="submit" name="commit" value="Save " data-disable-with="Save " />
  </div>
</form>
#config/routes.rb
Rails.application.routes.draw do

  resources :comments, only: [:new, :create]
  resources :advertisements
  resources :users, only: [:new, :create] do
    collection do
      get :login, to: 'sessions#new', as: "login"
      post :login, to: 'sessions#create'
      delete :logout, to: 'sessions#destroy', as: "logout"
    end
  end
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
#app/controllers/advertisements_controller.rb
before_action :set_advertisement, only: [:show, :edit, :update, :destroy]

...

# GET /advertisements/1
# GET /advertisements/1.json
def show
  @comments = @advertisement.comments.all
end

...

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

Я знаю, что hidden_fields и форма, подобная моей, вероятно, не лучший вариант для такого рода действий. но я все еще учусь. Спасибо за вашу помощь!

1 Ответ

0 голосов
/ 07 января 2020

Почему мой оригинальный код не сработал?

Наиболее вероятная причина в том, что вы передаете неправильное в частичное. Передача экземпляра объявления приведет к тому, что форма будет использовать путь /advertisements/1.

Какое лучшее решение?

Начните с создания вложенного маршрута :

# config/routes.rb
resources :advertisements do
  resources :comments, shallow: true
end

Это позволяет создавать комментарии для определенных c рекламных объявлений, отправляя запрос POST по адресу:

POST /advertisements/:advertisements_id/comments

Вы можете настроить форму для отправки по вложенному маршруту, передав массив:

#app/views/comments/_form.html.erb
<%= form_with(model: [local_assigns[:advertisement], comment], local: true) do |form| %>
  <div class="field">
    <%= form.text_area :content %>
  </div>

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

Использование local_assigns(:advertisement) позволяет использовать одно и то же частичное для вложенных и не вложенных представлений (редактирование / обновление), не рискуя ошибкой NoMethod, если она не пройдена. Массив сжимается, поэтому значение nil не имеет значения.

А затем настройте свой контроллер так, чтобы он использовал params[:advertisement_id], который будет передан как часть пути запроса и вместо этого получит идентификатор пользователя из сеанса.

#app/controllers/comments_controller.rb
class CommentsController < ApplicationController
  # callbacks help you avoid duplication
  before_action :set_advertisement, only: [:new, :create, :index]

  # GET /advertisements/1/comments/new
  def new
    @comment = @advertisement.comments.new
  end

  # POST /advertisements/1/comments
  def create
    @comment = @advertisement.comments.new(comment_params) do |c|
      c.user = current_user # here I'm assuming you have a method that fetches the user from the session
    end
    respond_to do |format|
      if @comment.save
        format.html { redirect_to @comment, notice: 'Comment was successfully created.' }
      else
        format.html { render :new }
      end
    end
  end

  private

    # Never trust parameters from the scary internet, only allow the white list through.
    def comment_params
      params.require(:comment).permit(:content)
    end

    def set_advertisement
      @advertisement = Advertisement.find(params[:advertisement_id])
    end
end

Убедитесь, что вы визуализируете партиал правильно:

<%= render 'comments/form', advertisement: @advertisement, comment: @comment %>

Для ссылки на «новое» действие вы можете использовать:

<%= link_to "Add a comment", new_advertisement_comment_path(@advertisement) %>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...