Я пробовал и form_tag
, и form_with
- результат тот же, действие контроллера никогда не срабатывает.
# routes.rb
resources :products do
member do
patch :add_comment
end
end
# products_controller.rb
def add_comment
# !!! damn form_with never gets here!!!
product.add_comment!(params[:comment_id])
redirect_back(fallback_location: products_path)
end
# view
<%= form_with(url: add_comment_product_path, local: true) do |form| %>
<%= form.text_field :comment_id %>
<%= form.submit 'Add comment' %>
<% end %>
Актуальные журналы:
Started PATCH "/products/1"
Processing by ProductsController#update as HTML
Parameters: {
"utf8"=>"✓",
"authenticity_token"=>"token",
"products"=>{a_lot: :of_stuff},
"comment_id"=>"2",
"commit"=>"Add comment",
"id"=>"1"
}
Ожидаемые журналы:
Started PATCH "/products/1/add_comment?comment_id=2"
Processing by ProductsController#add_comment as HTML
Parameters: {
"utf8"=>"✓",
"authenticity_token"=>"token",
"comment_id"=>"2",
"id"=>"1"
}
Редактировать:
Я думаю, это как-то связано с тем фактом, что этот form_with
вложен в более крупную форму, и, похоже, когда я нажимаю Add comment
, он запускает внешнюю отправку.
@BKSpurgeon, я думаю, это не имеет значения, дело в том, что я не могу выполнить действие контроллера с помощью form_tag
или form_with
. «Comment
» - это отдельная модель, но вопрос содержит очень упрощенную форму того, над чем я работаю (надеюсь, это очевидно). Основная цель - заставить form_with
вызывать правильное действие контроллера.
Где определяется form
? Вы вроде не передаете его блоку (т.е. form_with ... do |form|
)
@AbM хороший улов, это опечатка. Отредактировано
Что на выходе rake routes | grep add_comment_product
? Кроме того, вы должны передать идентификатор продукта в URL-адрес, то есть add_comment_product_path(some_id)
? Это приведет к созданию /products/1/add_comment
, а не /products/1/add_comment?comment_id=2
, поскольку вы не передаете comment_id
по URL-адресу.
Следует отметить, что стандарты HTML (как HTML5, так и более старые (x) HTML-стандарты) не допускают вложенных элементов <form>, и поведение может быть очень непредсказуемым, поскольку не указано, должен ли браузер использовать атрибут действия вложенной формы или переместите событие в родительский элемент формы, что, скорее всего, происходит в вашем случае. w3.org/TR/html5/forms.html
@AndreyDeineko, я спрашиваю, потому что в противном случае это вложенный ресурс, как указано в максе (см. Ответ макс ниже)
Эй, попробуй это -
# products_controller.rb
def add_comment
# You need add permitted for get parameters
params.permit(:comment_id)
product.add_comment!(params[:comment_id])
redirect_back(fallback_location: products_path)
end
# You can place this form anywhere in your application, but you need to specify product object and comment_id
<%- @product = Product.find(1) %>
<%= form_with(url: add_comment_product_path(@product, comment_id: 2), local: true, method: :patch) do |form| %>
<%= form.text_field :comment_id %>
<%= form.submit 'Add comment' %>
<% end %>
Started PATCH "/products/1/add_comment?comment_id=2" for 127.0.0.1 at 2018-10-05 22:01:37 +0600
Processing by ProductsController#add_comment as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"token", "comment_id"=>"2", "commit"=>"Add comment", "id"=>"1"}
пожалуйста, удали свой ответ. Это копировать вставить моего кода.
Пожалуйста, внимательно сравните со своим вопросом.
Я также был проверен, если вы не укажете метод, то по умолчанию это метод POST, вот мой журнал тестового приложения - Запущен POST "/ products / 2 / add_comment" для 127.0.0.1 в 2018-10-05 22:17:31 + 0600, ActionController :: RoutingError (Нет маршрута, соответствующего [POST] "/ products / 2 / add_comment")
add_comment_product PATCH /products/:id/add_comment(.:format) products#add_comment
Вы объявили его как маршрут член, но я не вижу, что вы передаете какое-либо значение для :id
помощника пути.
Попробуйте изменить его на
<%= form_with(url: add_comment_product_path(product), local: true) do |form| %>
где product
- это экземпляр Product
.
к сожалению, не имеет значения
@AndreyDeineko Это работает <%= form_with(model: @your_product_instance, url: add_comment_product_path, local: true) do |form| %>
?
add_comment_product_path(product)
фактически создаст правильный маршрут. Я считаю, что проблема в том, что вызов <%= form_with %>
вложен в другую форму, которая создает недопустимый HTML.
Rails справится с этим как с отдельным, но вложенным ресурсом - поскольку вы действительно создаете новый ресурс (комментарий), а не изменяете сам продукт.
Это также поддерживает ваш код в соответствии с принципом единой ответственности (SRP), поскольку каждый контроллер обрабатывает CRUD только для одного типа ресурса.
Вы можете ресурсы гнезда, вложив вызовы в resources
:
resources :products do
resources :comments, shallow: true
end
Затем настройте CommentsController для обработки комментариев CRUD:
class CommentsController < ApplicationController
before_action :set_comment, only: [:index, :new, :create]
# GET /products/:product_id/comments
def index
@comments = @product.comments
end
# GET /products/:product_id/comments/new
def new
@comment = @product.comments.new
end
# POST /products/:product_id/comments
def create
@comment = @product.comments.new(comment_params)
if @comment.save
redirect_to @product, success: 'Comment created'
else
render :new
end
end
# ...
private
def set_product
@product = Product.find(params[:product_id])
end
def comment_params
params.require(:comment)
.permit(:foo, :bar)
end
end
Чтобы установить атрибут действия формы так, чтобы он указывал на вложенный маршрут, вы просто используете массив или именованный помощник маршрута product_comments(product_id: @product.to_param)
.
<%= form_with(model: @comment, url: [@comment.product, @comment], local: true) do |form| %>
<%= form.submit 'Add comment' %>
<% end %>
Поскольку идентификатор продукта передается через URI, нет необходимости передавать его через скрытый ввод.
I think it has something to do with the fact that this form_with is nested into bigger form and it looks when I hit Add comment it triggers the outer submit
Следует отметить, что стандарты HTML (как HTML5, так и более старые (x) стандарты HTML) не допускают вложенных элементов формы, и поведение может быть очень непредсказуемым, поскольку не указано, должен ли браузер использовать атрибут действия вложенной формы или пузырек в родительский элемент формы, что, скорее всего, происходит в вашем случае. см .: http://w3.org/TR/html5/forms.html
Вы можете опустить действие index
и new
, если форма и отображение комментариев находятся на /products/:id
.
Я понял это после того, как поставил под сомнение редакцию. Я скоро протестирую вложенный ресурс, но я уверен, что это правильный путь. Маан, я не работал над представлениями уже несколько лет, просто тяжелые бэкэнд-штуки, совершенно забыл, как это просто. Спасибо за ответ, я дам вам знать, как все прошло, как только попробовал
Надеюсь, вы видели мой комментарий о том, что вложенные элементы <form>
не разрешены в стандартах HTML - это объясняет, почему форма не отправляется по ожидаемому маршруту.
Мне просто пришлось переместить вложенную форму из большей формы, чтобы она заработала.
В исходном комментарии запрашивались маршруты, и я просто увидел его тогда. Комментарий - это отдельный ресурс или в записи продукта есть comment_id?