Rails: Откуда form_with знает, какое действие контроллера вызывать?

В качестве примера взята эта форма:

<%= form_with model: @product do |f| %>
   <!-- ... --!>
<% end %>

Файл маршрутов:

get "/products", to: "products#index"
get "/products/new", to: "products#new"
post "/products", to: "products#create"
get "/products/:id", to: "products#show", as: "product"

Откуда он знает, что ему нужно вызвать действие create контроллера продуктов?

На чем основано решение?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
73
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

form_with угадывает маршрут по модели. Если модель является экземпляром Product и это new_record?, то это будет POST /products. Если это запись persisted?, то она будет PATCH /products/{:id} (см. Помощники форм в официальных руководствах Rails).

Это соответствует соглашениям Ruby on Rails и стандартному способу определения маршрутов с помощью rescources :products (см. Маршрутизация). Это создаст следующие маршруты:

GET       /products           => ProductsController#index 
GET       /products/new       => ProductsController#new 
POST      /products           => ProductsController#create 
GET       /products/:id       => ProductsController#show 
GET       /products/:id/edit  => ProductsController#edit 
PATCH/PUT /products/:id       => ProductsController#update 
DELETE    /products/:id       => ProductsController#destroy 

Обратите внимание, что вы не используете помощник resources для генерации маршрутов, когда from_with работает только тогда, когда вы определяете те же маршруты, что и Rails. В противном случае нам нужно будет передать дополнительный url: хелперу формы.

Я предлагаю прочитать о FormHelper#form_with в документации API Rails и взглянуть на реализацию этого метода.

Это объясняет, почему вы можете использовать один и тот же фрагмент для создания/создания, а также для редактирования/обновления. Большой! Большое спасибо.

cluster1 13.07.2024 09:36

Точно! Но важно, что это работает только тогда, когда вы следуете соглашениям об именах Rails.

spickermann 13.07.2024 09:46

@spickermann одно небольшое уточнение: с этого аспекта важны только вспомогательные методы. Пока в вашем приложении есть вспомогательный метод products_path/product_path, помощники по маршрутизации будут совершенно счастливы, даже если они вернут ерунду.

max 14.07.2024 17:16

Это не так.

form_with просто использует полиморфные помощники маршрутизации , чтобы найти вспомогательный метод маршрутизации, основанный на соглашении о конфигурации, и вызывает его динамически, чтобы получить путь для атрибута формы action.

Вспомогательные методы маршрутизации генерируются путем вызова макросов маршрутизации в вашем файле config/routes.rb и доступны в представлении и контроллерах. Когда вы вызываете resources :products, чтобы объявить обычные маршруты, он определяет вспомогательные методы products_path и product_path (и многие другие).

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

Контроллер назначения на самом деле имеет значение только после того, как пользователь отправит форму, и маршрутизатор Rails попытается сопоставить входящий HTTP-запрос с комбинацией контроллера и действия.

ActiveModel::Именование

Помощники полиморфной маршрутизации могут угадать, как называются помощники, с помощью API ActiveModel::Naming. Это просто предполагает, что маршруты, таблицы и т. д. могут быть получены из имени класса модели. Это огромная часть «магии» Rails, которая позволяет вашим моделям взаимодействовать с остальной частью фреймворка.

irb(main):006:0> class Product; include ActiveModel::Naming; end
=> Product
irb(main):007:0> Product.model_name
=>
#<ActiveModel::Name:0x00005570c2876c60
 @collection = "products",
 @element = "product",
 @human = "Product",
 @i18n_key=:product,
 @klass=Product,
 @name = "Product",
 @param_key = "product",
 @plural = "products",
 @route_key = "products",
 @singular = "product",
 @singular_route_key = "product",
 @uncountable=false>     

Новые и старые рекорды

polymorphic_url сначала выясняет, генерирует ли он путь к коллекции или путь к членам, вызывая new_record? в модели.

Если запись является новой записью или самим классом, она вызывает model_name.route_key и в конечном итоге вызывает хелпер пути к коллекции products_path.

Если модель сохраняется, она вызывает model_name.singular_route_key и передает model.to_param в качестве аргумента, что приводит к вызову помощника пути к члену product_path(product.to_param). to_param по умолчанию использует product.id в качестве идентификатора записи.

form_with также использует persisted?, чтобы определить, следует ли использовать HTTP-метод POST или PATCH для создания или обновления.

Другие вопросы по теме