我有一个模型书籍和一个模型作者。
添加书籍的表单,包含允许添加作者的嵌套。这样可行。但是,我在authors字段上有一个自动完成功能,所以当表单发布到控制器时,作者(几乎)肯定存在于数据库中。
我应该以某种方式对嵌套的属性进行find_or_initialize_by
。
我可能正在寻找错误的地方,但我在导轨指南中找不到这个。我试过这个(在SO上找到):
def create
@book = Book.new(params_book)
small_name = params[:book][:authors_attributes]["0"]["name"].downcase
aut_id = Author.where("\"authors\".\"name\" = :name",{name: small_name}).pluck(:id).join
@book.authors = Author.find_or_initialize_by(id: aut_id)
if @book.save
redirect_to see_book_url(Book.last)
else
render 'new'
end
end
这会产生错误:
undefined method `each' for #<Author:0x007fac59c7e1a8>
引用第@book.authors = Author.find_or_initialize_by(id: aut_id)
行
修改
在对这个问题的评论之后,我将代码更新为:
def create
book_params = params_book
small_name = params[:book][:authors_attributes]["0"]["name"].downcase
id = Author.where("\"authors\".\"name\" = :name",{name: small_name}).pluck(:id).join
book_params["authors_attributes"]["0"]["id"] = id
@book = Book.new(book_params)
if @book.save
redirect_to see_book_url(Biblio.last)
else
....
书籍参数如下:
<ActionController::Parameters {"title"=>"Testus Testa",
"authors_attributes"=><ActionController::Parameters {
"0"=><ActionController::Parameters {"name"=>"Vabien", "id"=>"22"}
permitted: true>} permitted: true>} permitted: true>
这对我来说很好,但是,我收到了这个错误:
ActiveRecord::RecordNotFound in Administration::BooksController#create
Couldn't find Author with ID=22 for Book with ID=
答案 0 :(得分:1)
好的,获得所需内容的最简单方法是更改表单中的自动填充,例如:['author 1 name', 'author 2 name']
将其更改为包含作者姓名和ID的对象数组:{ {1}}所以只要那个表单字段现在是“id”而不是“name”,那么在你的控制器中,你所要做的就是:
[{label: 'author 1 name', value: 0}, {label: 'author 2 name', value: 1}]
因为只有没有ID的属性才会被创建为新对象。 只需确保在图书模型中设置 def create
@book = Book.new(params_book)
if @book.save
redirect_to see_book_url(Book.last)
else
render 'new'
end
end
。
您获得的错误是因为accepts_nested_attributes_for :authors
是一个很多关系,因此当您将其设置为单个作者时,它会期望一个集合。要将单个作者添加到集合中,您执行@book.authors
而不是@book.authors << Author.find_or_initialize_by(id: aut_id)
,尽管其冗余用于使用名称来获取ID,只是用id初始化。 id将自动创建。请改用@book.authors = Author.find_or_initialize_by(id: aut_id)
。
在您当前的代码中,您创建了多个作者,这不仅是因为缺少“id”而是因为Author.find_or_initialize_by(name: small_name)
将嵌套属性传递给对象初始值设定项,然后在您访问嵌套属性参数之后并再次添加作者。此外,如果您有多个具有相同名称的作者,那么@book = Book.new(params_book)
实际上会从具有该名称的所有作者的组合ID中创建一个ID。
如果您想手动执行此操作,请在“params_book”方法中从许可中删除Author.where("\"authors\".\"name\" = :name",{name: small_name}).pluck(:id).join
,这样就不会将其传递给:authors_attributes
,然后执行以下操作:
Book.new
如果您遇到麻烦,请告诉我!
海报回复后
从“params_book”方法中删除许可证中的def create
@book = Book.new(params_book)
params[:book][:author_attributes].each{|k,v| @book.authors << Author.find_or_initialize_by(name: v['name'])}
if @book.save
redirect_to see_book_url(Book.last)
else
render 'new'
end
end
并尝试以下操作:
:authors_attributes
答案 1 :(得分:0)
解决了,非常感谢Jose Castellanos和这篇文章:
Adding existing has_many records to new record with accepts_nested_attributes_for
现在的代码是:
<requestfocus />