Почему мой URL-адрес Rails отображает URL-адрес с точкой, а не с косой чертой?

Прежде чем вдаваться в подробности, я прочитал эти сообщения, чтобы безуспешно попытаться найти решение: один, два, три

При этом: я [новичок] и создаю ecomm-сайт по продаже подержанной одежды, обуви и предметов декора.

В моей структуре есть только одна модель Product и связанный контроллер и таблица. Каждый «продукт» имеет одну из трех различных основных категорий, которые я использую, чтобы различать и создавать 3 разных URL-адреса.

Мои маршруты выглядят так:

Rails.application.routes.draw do

  root to: 'pages#home'

  get 'clothing', to: 'products#clothing'
  get 'clothing/:id', to: 'products#show'

  get 'shoes', to: 'products#shoes'
  get 'shoes/:id', to: 'products#show'

  get 'home', to: 'products#home'
  get 'home/:id', to: 'products#show'

  get 'products/new', to: 'products#new'
  post 'products', to: 'products#create'

end

Мой products_controller выглядит так:

class ProductsController < ApplicationController
  before_action :set_all_products
  before_action :set_one_product, only: [:show]

  def shoes
    @all_shoe_products = @all_products.where(main_category_id: MainCategory.find_by_name("shoes").id)
  end

  def clothing
    @all_clothing_products = @all_products.where(main_category: MainCategory.find_by_name("clothes").id)
  end

  def home
    @all_home_products = @all_products.where(main_category: MainCategory.find_by_name("housewares").id)
  end

  def show
  end

  def new
    @new_product = Product.new
  end

  private

  def set_one_product
    @product = Product.find(params[:id])
  end

  def set_all_products
    @all_products = Product.all
  end
end

И при записи <%= link_to clothing_path(product) %> ('product' является заполнителем в цикле .each) я получаю путь: root/clothing.[:id], а не root/clothing/[:id].

Я знаю, что делаю ошибку соглашения, и попытка иметь 3 разных URL-адреса в одном контроллере может оказаться там, где я ошибаюсь.

Примечание. Если вручную ввести root/clothing/[:id] в адресную строку, товар будет возвращен правильно.

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

Ответы 5

Когда вы это сделаете:

get 'clothing', to: 'products#clothing'
get 'clothing/:id', to: 'products#show'

в вашем routes.rb он создает эти маршруты (которые вы можете увидеть, выполнив rake routes в вашей консоли):

clothing GET    /clothing(.:format)         products#clothing
         GET    /clothing/:id(.:format)     products#show

Как видите, clothing_path направляется к /clothing, а не к /clothing/:id. Итак, когда вы это сделаете:

<%= link_to clothing_path(product) %>

rails добавляет идентификатор как .id (что вы и испытываете).

Привет и спасибо за то, что уделили время ответу. Это я полностью понимаю, но не знаю, как это исправить? Я знаю, что обычное соглашение в показатель и показывать в контроллере - это пути множественное число и единственное число соответственно - хотя я не уверен, как расколоть этот орех здесь

brian-welch 14.12.2018 10:16

Рад, что это прояснило ситуацию. Кстати, ваш вопрос был: «Почему мой URL-адрес Rails отображает URL-адрес с точкой, а не с косой чертой?». Итак, я ответил на этот вопрос. «Как починить?», «Как уберечь рельсы от…» и т. д. - это разные вопросы.

jvillian 14.12.2018 20:15

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

Это может быть немного больше работы, хотя вам, вероятно, будет лучше с отдельными контроллерами для shoes, clothing и home и следовать дизайну RESTful. Это позволит вам использовать resources в вашем файле маршрутов.

Например, ваш shoes_controller.rb будет выглядеть следующим образом:

class ShoesController < ApplicationController
  before_action :set_all_products
  before_action :set_one_product, only: [:show]

  def index
    @all_shoe_products = @all_products.where(main_category_id: MainCategory.find_by_name("shoes").id)
  end

  def show
  end

  private

  def set_one_product
    @product = Product.find(params[:id])
  end

  def set_all_products
    @all_products = Product.all
  end
end

И тогда маршруты для их определения будут:

resources :shoes, only: [:index, :show]

Вы следуете этому шаблону для других ресурсов, и у вас будет красиво разделенный код, соответствующий хорошим соглашениям Rails.

Это сгенерирует маршруты по мере того, как вы:

shoes   GET    /shoes(.:format)        shoes#index
shoe    GET    /shoe/:id(.:format)     shoes#show

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

Надеюсь, это поможет - дайте мне знать, если у вас возникнут какие-либо вопросы или отзывы.

Я нашел решение, хотя мне кажется логической загадкой, почему оно работает.

В маршрутах .....

  get 'clothing', to: 'products#clothing'
  get 'clothing/:id', to: 'products#show', as: 'clothing/item'

На странице показатель ....

  <%= link_to clothing_item_path(product) do %>

Это дает правильную структуру URL: root/clothing/[:id]

Во время тестирования я ожидал: root/clothing/item/[:id] ... хотя я предпочитаю результат моим ожиданиям

Рад, что у тебя все получилось. Я полагаю, что это результат того, что Rails продезинфицировал / в as: 'clothing/item' до подчеркивания: вы бы достигли того же результата с as: 'clothing_item', который, возможно, немного более читабелен. Я бы порекомендовал прочитать мой ответ - на ранних этапах стоит потратить время, чтобы правильно структурировать приложение, что может избежать изрядной боли в дальнейшем :) Надеюсь, что остальная часть проекта пойдет хорошо.

SRack 14.12.2018 10:44

Я думаю, что вам нужны параметризованные маршруты, например:

get ':product_line', to: 'products#index'
get ':product_line/:id', to: 'products#show'

Это позволит вам создавать любое количество пользовательских линеек продуктов без необходимости определять новые методы в вашем контроллере. Если предположить, что в вашей модели product_line есть атрибут Product, контроллер будет выглядеть так:

class ProductsController < ApplicationController
  def index
    @product_line = params[:product_line]
    @products = Product.where(product_line: @product_line)
  end

  def show
    @product_line = params[:product_line]
    @product = Product.find(params[:id])
  end
end

И ваши views / products / index.html.erb будут выглядеть так:

<p id = "notice"><%= notice %></p>

<h1><%= @product_line %></h1>

<table>
  <thead>
    <tr>
      <th>Description</th>
      <th>Price</th>
      <th></th>
    </tr>
  </thead>

  <tbody>
    <% @products.each do |product| %>
      <tr>
        <td><%= product.description %></td>
        <td><%= product.price %></td>
        <td><%= link_to 'Show', "#{@product_line}/#{product.id}" %></td>
      </tr>
    <% end %>
  </tbody>
</table>

Обратите внимание, что link_to больше не может использовать вспомогательный метод Rails для генерации URL-адреса. Тебе придется сделать это самому.

Прелесть этого подхода заключается в том, что пользователи могут вводить ЛЮБУЮ линейку продуктов в URL-адрес. Если у вас была эта линейка продуктов (например, «sporting_goods»), покажите ее. Если нет, отобразите страницу с благодарностью за проявленный интерес и зарегистрируйте тот факт, что кто-то запросил эту линейку продуктов, чтобы вы могли оценить интерес по мере расширения своих предложений.

К тому же это ОТДЫХ! Ура!

Способ решения этой проблемы в Rails - создание вложенного ресурса:

resources :categories do
  resources :products, shallow: true
end

Это вложит маршруты сбора так, чтобы вы получили GET /categories/:category_id/products.

Хотя это может быть не так коротко, как ваши тщеславные маршруты, но он гораздо более универсален, поскольку позволяет вам показывать продукты для любой потенциальной категории без раздувания вашей кодовой базы.

Вы бы настроили контроллер так:

class ProductsController < ApplicationController
  before_action :set_category, only: [:new, :index, :create]

  # GET /categories/:category_id/products
  def index
    @products = @category.products
  end

  # GET /categories/:category_id/products/new
  def new
    @product = @category.products.new
  end

  # POST /categories/:category_id/products
  def new
    @product = @category.products.new(product_params)
    # ...
  end

  # ...

  private
    def set_category
      @category =  MainCategory.includes(:products)
                               .find_by!('id = :x OR name = :x', x: params[:id])
    end
end

Вы можете ссылаться на продукты любой категории, используя помощник по именованному пути category_products_path:

link_to "#{@category.name} products", category_products_path(category: @category)

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

link_to "#{@category.name} products", [@category, :products]
form_for [@category, @product]
redirect_to [@category, :products]

Если вы хотите направить невложенный GET /products и вложенный GET /categories/:category_id/products к разным контроллерам, можно использовать опцию модуля:

resources :products

resources :categories do
  resources :products, only: [:new, :index, :create], module: :categories
end

Это направит вложенные маршруты к Categories::ProductsController.

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