Как создать ребенка, прежде чем связать его с родителем в рельсах? - PullRequest
0 голосов
/ 09 апреля 2020

У меня есть Категории (родители) , в которых перечислены Продукты (дети) .

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

Тем не менее, я получаю сообщение об ошибке:

NoMethodError in Products#new
Showing /Users/istvanlazar/Mobily/app/views/products/new.html.erb where line #9 raised:

undefined method `products_path' for #<#<Class:0x00007febaa5aec98>:0x00007febae0f9e38>
Did you mean?  product_show_path 

## product_show_path is a custom controller that has nothing to do with this one, 
enabling show and clean redirection from newest_products index bypassing categories nesting.

Extracted source (around line #9):
9  <%= form_for [@product] do |f| %>
10   <div class="form-styling">
11     <div>
12       <%= f.label :name %>

Мое приложение работает следующим образом:

Модели

class Category < ApplicationRecord
  has_many :products, inverse_of: :category
  accepts_nested_attributes_for :products

  validates :name, presence: true
end


class Product < ApplicationRecord
  belongs_to :user, optional: true
  belongs_to :category, inverse_of: :products

  validates :category, presence: true
end

Маршруты

get 'products/new', to: 'products#new', as: 'new_product'

resources :categories, only: [:index, :show, :new, :edit] do
  resources :products, only: [:index, :show, :edit]
  # resources :products, only: [:index, :show, :new, :edit]
end

Контроллеры

class ProductsController < ApplicationController
  before_action :set_category, except: :new

  def index
    @products = Product.all
    @products = policy_scope(@category.products).order(created_at: :desc)
  end

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

  def new
    @product = Product.new
    @product.user = current_user
  end

  def create
    @product = Product.new(product_params)
    @product.user = current_user
    if @product.save!
      redirect_to category_product_path(@category, @product), notice: "Product has been successfully added to our database"
    else
      render :new
    end
  end

  private

  def set_category
    @category = Category.find(params[:category_id])
  end

  def product_params
    params.require(:product).permit(:name, :price, :description, :category_id, :user, :id)
  end
end


class CategoriesController < ApplicationController
  def index
    @categories = Category.all    
  end

  def show
    @category = Category.find(params[:id])
  end

  def new
    # Non-existant created in seeds.rb
  end

  def create
    # idem
  end

  def edit
    # idem
  end

  def update
    # idem
  end

  def destroy
    # idem
  end

  private

  def category_params
    params.require(:category).permit(:name, :id)
  end
end

Просмотров

# In shared/navbar.html.erb:

<nav>
  <ul>
    <li>Some Link</li>
    <li>Another Link</li>
    <li><%= link_to "Create", new_product_path %></li>
  </ul>
</nav>

# In products/new.html.erb:

<%= form_for [@product] do |f| %>
    <div class="form-styling">
      <div>
        <%= f.label :name %>
        <%= f.text_field :name, required: true, placeholder: "Enter product name" %>

        <%= f.label :price %>
        <%= f.number_field :price, required: true %>
      </div>
      <div>
        <%= f.label :description %>
        <%= f.text_field :description %>
      </div>
      <div>
        <%= f.label :category %>
        <%= f.collection_select :category_id, Category.order(:name), :id, :name, {prompt: 'Select a Category'}, required: true %>
      </div>
      <div>
        <%= f.submit %>
      </div>
    </div>
  <% end %>

Есть ли у вас какие-либо идеи о том, где что пошло не так? Или невозможно создать ребенка до того, как назначить его родителю ..?

Заранее спасибо.

Best, Ist

Ответы [ 2 ]

1 голос
/ 09 апреля 2020

Вы не определили какой-либо маршрут для обработки POST новой формы продукта. Вы определили путь new_product, но это соглашение нарушает соглашения Rails, и вы не предоставляете обходной путь.

Вы можете определить другой пользовательский маршрут, например, post 'products', to: 'products#create', as: 'create_new_product', а затем установить его в вашей форме, например form_for @product, url: create_new_product_path do |f|.

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

0 голосов
/ 09 апреля 2020

Редактировать: Я неправильно понял намерение, игнорировать это. Go с ответом Джереми Уэзера.

Или невозможно создать ребенка, прежде чем назначить его родителю ..?

Как вы ваши отношения и проверки настроены: да, это так. Продукт требует категории, через validates :category, presence: true. И если вы находитесь на Rails 5+, ассоциация уже потребуется по умолчанию (это означает, что validates фактически избыточно). Это означает, что если вы попытаетесь создать Продукт без Категории, он потерпит неудачу, и Продукт не будет сохранен в базе данных.

С этим ограничением я рекомендую попробовать следующее:

  • Удалить пользовательский /products/new маршрут
    • удалить get 'products/new', to: 'products#new', as: 'new_product'
  • Добавить: новые и: создать маршруты, позволяющие создавать продукты, вложенные в категории
    • Добавьте :create и :new к массиву :only в resources :products, вложенном в resources :categories
  • Переместите файл views/products/new.html.erb в views/categories/products/new.html.erb (при необходимости создайте новый каталог categories в views).
  • В этом файле измените form_for, чтобы форма отправляла сообщения во вложенный каталог: create route:
    • form_for [@category, @product] do |f|
  • Посетите URL /categories/[insert some Category ID here]/products/new, заполнив некоторые данные, и посмотрите, работает ли это.

Ваш route.rb должен выглядеть следующим образом :

resources :categories, only: [:index, :show, :new, :edit] do
  resources :products, only: [:index, :show, :new, :create, :edit]
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...