我有一个Word模型和一个分类模型。
单词has_and_belongs_to_many类别。 分类has_and_belongs_to_many单词。
现在,我已在控制台中设置并运行所有内容,例如:
Word.create(title: "Testicles")
testicles = Word.first
Category.create(title: "Genitalia")
genitalia = Category.first
testicles.categories << genitalia
testicles.categories
=> "genitalia"
现在我也可以在视图中使用表单来启动和运行,但前提是我在单独的页面上以自己的形式单独创建了类别,并且与Word相同。然后在Word show视图中,我可以创建一个表单来为其分配类别。
但是......我真正想要做的就是在我创建Word时,即在“新词”视图上同时完成所有这些操作。
我在解决如何做到这一点时遇到了很大的问题。我想我说我在这个视图中只能有一个表单和一个提交,所以我想我不得不将所有内容从该表单发送到WordsController,并且工作那里有一些魔力,但到底该做什么让我头疼不已。有人可以帮忙吗?
我还没有创建用户模型或设置身份验证,因此在这方面没有障碍。
模型/ word.rb:
class Word < ActiveRecord::Base
belongs_to :user
has_and_belongs_to_many :categories
validates :title, presence: true
end
模型/ category.rb:
class Category < ActiveRecord::Base
has_and_belongs_to_many :words
validates :title, presence: true
end
schema.rb:
ActiveRecord::Schema.define(version: 20150529144121) do
create_table "categories", force: :cascade do |t|
t.string "title"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "categories_words", id: false, force: :cascade do |t|
t.integer "category_id"
t.integer "word_id"
end
add_index "categories_words", ["category_id"], name: "index_categories_words_on_category_id"
add_index "categories_words", ["word_id"], name: "index_categories_words_on_word_id"
create_table "words", force: :cascade do |t|
t.string "title"
t.text "description"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "words", ["user_id"], name: "index_words_on_user_id"
end
在尝试各种form_tag魔法(并且失败严重)后,目前我正在使用此表单:
<%= form_for(@word) do |f| %>
<% if @word.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@word.errors.count, "error") %> prohibited this word from being saved:</h2>
<ul>
<% @word.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title, 'Word' %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :description, 'Definition' %><br>
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :categories, 'Category' %><br>
<%= f.text_field :categories %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
在视图中,表单包含:
#<Category::ActiveRecord_Associations_CollectionProxy:0x007f16dd834820>
<类别'框中的,但可以清除此项并输入您自己的类别。在提交填写了所有字段的表单时,我会收到NoMethodError。
答案 0 :(得分:2)
所以基本上你想同时创建一个单词和一个类别,然后链接它们。如果经典解决方案(例如使用nested_form
宝石)不能完全按照您的意愿行事,那么您可以尝试这种方法。
您真的需要一个自定义视图/控制器,并按照您的建议在控制器中执行业务。我建议您使用简单的form_tag
来添加一些字段集。
视图的
<%= form_tag your_custom_route_path, :html => {:class => "form-horizontal"} do |form| %>
<%= fields_for :word, @word do |f| %>
<%= f.text_field :title %>
<% end %>
<%= fields_for :category, @category do |f| %>
<%= f.text_field :title %>
<% end %>
<% end %>
路由
post '/yourRoute', to: 'your_controller#your_action_create', as: 'your_custom_route'
控制器具有一些动作
class YourController < ApplicationController
# new
def your_action_new
@word = Word.new
@category = Category.new
end
# Post
def your_action_create
@word = Word.new(word_params)
@category = Category.new(category_params)
if @word.save and @category.save
@word.categories << @category
@word.save
end
end
private
def words_params
params.require(:word).permit(:title, ...)
end
def category_params
params.require(:category).permit(:title...)
end
答案 1 :(得分:0)
感谢Cyril DD的帮助,我对此进行了扩展并创建了一个表单和自定义控制器,它将创建一个新的Word,并为其分配一个新的类别和/或用户可以分配现有的类别那个新词。
_form.html.erb:
<%= form_tag(controller: "new_word", action: "create_word_and_category", method: "post") do %>
<% if @word.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@word.errors.count, "error") %> prohibited this category from being saved:</h2>
<ul>
<% @word.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= fields_for :word, @word do |word_form| %>
<div class="field">
<%= word_form.label(:title, "Word:") %><br>
<%= word_form.text_field(:title, id: "new_word", required: true) %>
</div>
<div class="field">
<%= word_form.label(:description, "Definition:") %><br>
<%= word_form.text_area(:description) %>
</div>
<% end %>
<%= fields_for :category, @category do |category_form| %>
<% if Category.count > 0 %>
<div class="field">
<%= category_form.label(:title, "Choose from existing Categories:") %><br>
<%= category_form.collection_check_boxes(:category_ids, Category.all, :id, :title) %>
</div>
<% end %>
<h4>AND/OR...</h4>
<div class="field">
<%= category_form.label(:title, "Create and Use a New Category:") %><br>
<%= category_form.text_field(:title) %>
</div>
<% end %>
<div class="actions">
<%= submit_tag("Create") %>
</div>
<% end %>
new_word_controller.rb(它还没有完全完成,但它已经完成了它在锡上所说的内容):
class NewWordController < ApplicationController
def create_word_and_category
@word = Word.new(word_params)
if @word.save
(params["category"])["category_ids"].each do |i|
next if i.to_i == 0
@word.categories << Category.find(i.to_i) unless @word.categories.include?(Category.find(i.to_i))
end
if category_params.include?(:title) && ((params["category"])["title"]) != ""
@word.categories << Category.new(title: (params["category"])["title"])
end
end
if @word.save
redirect_to words_path, notice: 'Word was successfully created.'
else
redirect_to new_word_path, notice: 'A valid word was not submitted.'
end
end
private
# Use callbacks to share common setup or constraints between actions.
# def set_word
# @word = Word.find(params[:id])
# end
# Never trust parameters from the scary internet, only allow the white list through.
def word_params
params.require(:word).permit(:title, :description, :user_id)
end
def category_params
params.require(:category).permit(:title, :category_ids, :category_id)
end
end
在我的routes.rb中:
post 'create_word_and_category' => 'new_word#create_word_and_category'
我打算将控制器代码放入旧的words_controller中,因为我没有看到需要将它放在像这样的单独控制器中。如果有人有任何想法/批评,那很好。如果有人能帮助我为这个控制器代码编写一个rspec控制器测试,那就更好了!我遇到了麻烦。