Ruby on rails 接受\u嵌套\u属性\u的备选方案-可能是virtus
我对rails比较陌生,最终找到了正确的方法来使用Ruby on rails 接受\u嵌套\u属性\u的备选方案-可能是virtus,ruby-on-rails,ruby,nested-forms,nested-attributes,Ruby On Rails,Ruby,Nested Forms,Nested Attributes,我对rails比较陌生,最终找到了正确的方法来使用accepts\u nested\u attributes\u for 然而,网络上有一些严肃的资源说,使用接受的嵌套属性通常是一种不好的做法(像这样) 为避免接受的_嵌套的_属性_,需要做哪些更改?您会将附加类文件放在哪个文件夹中(我想您需要一个附加类) 我读到这是合适的。是这样吗 下面是一个非常基本的示例,仍然使用接受的嵌套属性(查找完整示例): 型号 class Person < ActiveRecord::Base has
accepts\u nested\u attributes\u for
然而,网络上有一些严肃的资源说,使用接受的嵌套属性通常是一种不好的做法(像这样)
为避免接受
的_嵌套的_属性_,需要做哪些更改?您会将附加类文件放在哪个文件夹中(我想您需要一个附加类)
我读到这是合适的。是这样吗
下面是一个非常基本的示例,仍然使用接受
的嵌套属性(查找完整示例):
型号
class Person < ActiveRecord::Base
has_many :phones
accepts_nested_attributes_for :phones
end
class Phone < ActiveRecord::Base
belongs_to :person
end
class-Person
控制器
class PeopleController < ApplicationController
def new
@person = Person.new
@person.phones.new
end
def create
@person = Person.new(person_params)
@person.save
redirect_to people_path
end
def index
@people = Person.all
end
private
def person_params
params.require(:person).permit(:name, phones_attributes: [ :id, :number ])
end
end
class PeopleController
查看(people/new.html.erb)
[编辑]
使用服务对象是一个好主意吗?Railscasts也有一个关于嵌套表单模型的插曲:
如评论所示,cocoon gem简化了很多:
你的问题意味着你认为接受嵌套属性功能是一件坏事,但事实并非如此,而且效果非常好
我首先要说的是,你不需要一个替代方法来接受嵌套的属性,但我会在这篇文章的最后讨论这个问题
关于你提供的链接,它没有提到为什么海报认为接受嵌套属性应该被弃用,而只是声明
依我的拙见,应该反对这种做法
嵌套属性是一个非常重要的概念,当考虑如何以单一形式捕获与父级相关的多个记录时,它不仅是Ruby on Rails的东西,而且在大多数复杂的web应用程序中用于从浏览器将数据发送回服务器,而不考虑用于开发站点的语言
我根本没有批评你指的那篇文章。对我来说,这只是指出了用大量与业务逻辑无关的代码填充数据库支持模型的明显替代方案。所使用的具体示例仅是编码样式首选项备选方案
当时间是金钱,压力是巨大的,一行代码就可以完成任务,而示例中显示的22行代码则是如此。在大多数情况下(并非所有情况下),我的首选是在模型中使用一行代码(接受嵌套属性)来接受从表单发回的嵌套属性
正确回答您的问题是不可能的,因为您实际上没有说明为什么您认为接受\u嵌套的\u属性\u是不好的做法,但是最简单的替代方法是在控制器操作中提取参数散列属性,并在事务中单独处理每条记录
更新-跟进评论
我认为这篇链接文章的作者认为:
在oop范例中,每个对象应该只读取和写入自己的数据。
但是,对于接受嵌套的属性,一个对象会改变某些属性
其他对象数据
好的,让我们澄清一下。
首先,OO范式没有提出这样的问题。类应该是谨慎的,但允许它们与其他类交互。事实上,如果是这样的话,Ruby中的OO方法就没有意义了,因为Ruby中的所有东西都是一个类,因此任何东西都不能与其他任何东西进行对话。想象一下,如果恰好是控制器实例的对象无法与模型或其他控制器交互,会发生什么情况
但是,对于接受嵌套的属性,一个对象会改变某些属性
其他对象数据
关于这句话,我有几点要说,因为它很复杂,所以我会尽量简短
1) 模型实例保护数据。在涉及任何/大多数其他语言(C、Delphi、VB等)的数百个表的非常复杂的场景中,三层解决方案中的中间层就是这样做的。在Rails术语中,模型是业务逻辑的场所,在通常由RDBMS中的存储过程和视图进行备份的3层解决方案中,模型负责中间层的工作。模特们应该能够相互交谈,这是非常正确的
2) 接受的\u嵌套的\u属性\u根本不违反任何OO原则。它只是简化了如果该方法不存在(正如您所发现的)您将需要编写的代码量。如果您接受嵌套在子模型的params散列中的属性,那么您所做的就是允许子模型以与控制器操作相同的方式处理该数据。不绕过任何业务逻辑,您将获得额外的好处
最后
我可以负担得起对代码优雅的关心(比时间更重要)
我可以向您保证,编写超过您需要的20多行代码,并从一个gem中添加数百行代码,其中一行代码就可以为您完成工作,这并不是什么优雅的事情。正如其他人(包括我)所说的,接受\u嵌套的\u属性\u并不总是一个合适的ActiveRecord方法,通过查看不同的方法,最终您将能够更好地判断
<%= form_for @person, do |f| %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<%= f.fields_for :phones do |builder| %>
<p>
<%= builder.label :number %><br />
<%= builder.text_field :number %>
</p>
<% end %>
<%= f.submit %>
<% end %>
class Contact
include Virtus
extend ActiveModel::Naming
include ActiveModel::Conversion
include ActiveModel::Validations
attr_reader :name
attr_reader :number
attribute :name, String
attribute :number, Integer
def persisted?
false
end
def save
if valid?
persist!
true
else
false
end
end
private
def persist!
@person = Person.create!(name: name)
@phones = @person.phones.create!(number: number)
end
end
class ContactsController < ApplicationController
def new
@contact = Contact.new
end
def create
@contact = Contact.new(contact_params)
@contact.save
redirect_to people_path
end
def contact_params
params.require(:contact).permit(:name, :number)
end
end
<%= form_for @contact do |f| %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<p>
<%= f.label :number %><br />
<%= f.text_field :number %>
</p>
<%= f.submit %>
<% end %>
class ContactListForm
include ActiveModel::Model
attr_accessor :contacts
def contacts_attributes=(attributes)
@contacts ||= []
attributes.each do |i, contact_params|
@contacts.push(Contact.new(contact_params))
end
end
end
class ContactsController < ApplicationController
def new
@contact_list = ContactListForm.new(contacts: [Contact.new])
end
end