Почему мой маршрут в Rails URL отображает URL с точкой, а не с косой чертой? - PullRequest
0 голосов
/ 14 декабря 2018

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

Это, как говорится: я [новое и] строю сайт 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] в адресной строке приводит кверните товар правильно.

Ответы [ 5 ]

0 голосов
/ 15 декабря 2018

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.

0 голосов
/ 14 декабря 2018

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

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

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

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»), продолжайте показывать ее.Если нет, предоставьте страницу с благодарностью за их интерес и запишите тот факт, что кто-то запросил эту линейку продуктов, чтобы вы могли повысить интерес по мере расширения своих предложений.

Плюс, это RESTful!Ура!

0 голосов
/ 14 декабря 2018

@ 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

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

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

0 голосов
/ 14 декабря 2018

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

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

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

В индексе page ....

  <%= link_to clothing_item_path(product) do %>

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

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

0 голосов
/ 14 декабря 2018

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

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 (это то, что вы испытываете).

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