如何在将 Child 关联到 rails 中的 Parent 之前创建它?
How to create a Child before associating it to its Parent in rails?
我有 类别 (Parents),其中列出了 产品 (Children)。
我希望能够在应用程序的任何位置直接从导航栏创建新产品,然后在创建过程中将其分配给类别。
但是,我得到了当前的错误:
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 %>
你知道哪里出了问题吗?还是 不可能在将 Child 分配给 Parent 之前创建 Child..?
提前致谢。
最好,
我
您还没有定义任何路由来处理您的新产品表单 POST。您已经定义了 new_product
路径,但这种安排打破了 Rails 的约定,您没有提供解决方法。
您可以定义另一个自定义路由,例如post 'products', to: 'products#create', as: 'create_new_product'
然后在你的表单中设置它 form_for @product, url: create_new_product_path do |f|
.
但是,您应该考虑更改结构,使产品路线不嵌套在类别下。在以这种方式打破常规之前三思。
编辑:误读原意,无视。采纳 Jeremy Weather 的回答。
Or is it impossible to Create a Child before assigning it to a Parent..?
通过建立关系和验证的方式:是的。一个产品需要一个类别,通过 validates :category, presence: true
。如果您使用的是 Rails 5+,则默认情况下已经需要关联(这意味着 validates
实际上是多余的)。这意味着如果您尝试创建没有类别的产品,它将失败,并且产品不会保存到数据库中。
有了这个限制,我建议您尝试以下方法:
- 删除自定义
/products/new
路线
- 移除
get 'products/new', to: 'products#new', as: 'new_product'
- 添加 :new 和 :create 路由以允许在类别下嵌套创建产品
- 将
:create
和 :new
添加到嵌套在 resources :categories
下的 :only
数组中
- 将文件
views/products/new.html.erb
移动到 views/categories/products/new.html.erb
(如有必要,在 views
中创建一个新的 categories
目录)。
- 在该文件中,更改
form_for
以便表单 POST 到嵌套的 :create 路由:
form_for [@category, @product] do |f|
- 访问 URL
/categories/[insert some Category ID here]/products/new
,填写一些数据,看看是否有效。
您的 routes.rb 应如下所示:
resources :categories, only: [:index, :show, :new, :edit] do
resources :products, only: [:index, :show, :new, :create, :edit]
end
我有 类别 (Parents),其中列出了 产品 (Children)。
我希望能够在应用程序的任何位置直接从导航栏创建新产品,然后在创建过程中将其分配给类别。
但是,我得到了当前的错误:
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 %>
你知道哪里出了问题吗?还是 不可能在将 Child 分配给 Parent 之前创建 Child..?
提前致谢。
最好, 我
您还没有定义任何路由来处理您的新产品表单 POST。您已经定义了 new_product
路径,但这种安排打破了 Rails 的约定,您没有提供解决方法。
您可以定义另一个自定义路由,例如post 'products', to: 'products#create', as: 'create_new_product'
然后在你的表单中设置它 form_for @product, url: create_new_product_path do |f|
.
但是,您应该考虑更改结构,使产品路线不嵌套在类别下。在以这种方式打破常规之前三思。
编辑:误读原意,无视。采纳 Jeremy Weather 的回答。
Or is it impossible to Create a Child before assigning it to a Parent..?
通过建立关系和验证的方式:是的。一个产品需要一个类别,通过 validates :category, presence: true
。如果您使用的是 Rails 5+,则默认情况下已经需要关联(这意味着 validates
实际上是多余的)。这意味着如果您尝试创建没有类别的产品,它将失败,并且产品不会保存到数据库中。
有了这个限制,我建议您尝试以下方法:
- 删除自定义
/products/new
路线- 移除
get 'products/new', to: 'products#new', as: 'new_product'
- 移除
- 添加 :new 和 :create 路由以允许在类别下嵌套创建产品
- 将
:create
和:new
添加到嵌套在resources :categories
下的
:only
数组中 - 将
- 将文件
views/products/new.html.erb
移动到views/categories/products/new.html.erb
(如有必要,在views
中创建一个新的categories
目录)。 - 在该文件中,更改
form_for
以便表单 POST 到嵌套的 :create 路由:form_for [@category, @product] do |f|
- 访问 URL
/categories/[insert some Category ID here]/products/new
,填写一些数据,看看是否有效。
您的 routes.rb 应如下所示:
resources :categories, only: [:index, :show, :new, :edit] do
resources :products, only: [:index, :show, :new, :create, :edit]
end