Rails 3.2 대량 할당을 통해 여러 새 항목을 제출하는 방법
꽤 표준적인 사용 사례가 있습니다. 부모 개체와 자식 개체 목록이 있습니다. 한 번에 모든 하위 항목을 테이블의 행으로 편집 할 수있는 테이블 형식을 원합니다. 또한 하나 이상의 새 행 을 삽입 하고 제출시 새 레코드로 만들 수 있기를 원합니다 .
나는를 사용하는 경우 fields_for
가-많은 관련 중첩 된 레코드에 대한 하위 형태의 시리즈를 렌더링, 레일 예를 들어, 필드 이름을 생성 parent[children_attributes][0][fieldname]
, parent[children_attributes][1][fieldname]
등등.
이로 인해 Rack은 다음과 같은 params 해시를 구문 분석합니다.
{ "parent" => {
"children" => {
"0" => { ... },
"1" => { ... } } }
전달 된 때 새 (유엔 지속) 개체를 동일 fields_for
필드 이름을 생성합니다 외모와 같은 것을 :
parent[children_attributes][][fieldname]
[]
색인이없는 것을 참고하십시오 .
이것은 할 수 있는 필드가 포함와 같은 형식으로 게시 [0]
, [1]
등 랙 혼란과 인상됩니다 있기 때문에
TypeError: expected Array (got Rack::Utils::KeySpaceConstrainedParams)
"OK"라고 생각합니다. " 모든 필드가 []
양식 대신 양식을 사용하도록 할 것입니다 [index]
. 그러나이 fields_for
작업을 일관되게 수행 하는 방법을 알 수 없습니다 . 명시적인 필드 이름 접두사를 제공하더라도 및 개체 :
fields_for 'parent[children_attributes][]', child do |f| ...
너무 오래로 child
유지됩니다 자동으로 그들이 예를 들면하게되도록 fieldName에 수정됩니다 parent[children_attributes][0][fieldname]
새로운 기록을 위해 fieldName에를 떠나있는 동안, parent[children_attributes][][fieldname]
. 다시 한번, Rack barfs.
나는 헤매고있다. 표준 Rails 헬퍼를 사용 하여 기존 레코드와 함께 fields_for
여러 개의 새 레코드 를 제출 하고, 매개 변수에서 배열로 구문 분석하고, ID가없는 모든 레코드를 DB에서 새 레코드로 생성하도록하려면 어떻게해야합니까? 운이 좋지 않고 모든 필드 이름을 수동으로 생성해야합니까?
다른 사람들이 언급했듯이 []
에 새 레코드에 대한 키를 포함해야합니다. 그렇지 않으면 해시를 배열 유형과 혼합하기 때문입니다. child_index
fields_for 의 옵션으로이를 설정할 수 있습니다 .
f.fields_for :items, Item.new, child_index: "NEW_ITEM" # ...
나는 일반적으로 object_id
여러 새 항목이있는 경우 고유한지 확인하기 위해 대신을 사용하여 수행 합니다.
item = Item.new
f.fields_for :items, item, child_index: item.object_id # ...
다음은이를 수행하는 추상 도우미 메서드입니다. 이것은 item_fields
렌더링 할 이름이있는 부분이 있다고 가정합니다 .
def link_to_add_fields(name, f, association)
new_object = f.object.send(association).klass.new
id = new_object.object_id
fields = f.fields_for(association, new_object, child_index: id) do |builder|
render(association.to_s.singularize + "_fields", f: builder)
end
link_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("\n", "")})
end
이렇게 사용할 수 있습니다. 인수는 링크 이름, 상위 양식 작성기 및 상위 모델에 대한 연관 이름입니다.
<%= link_to_add_fields "Add Item", f, :items %>
그리고 여기에 해당 링크의 클릭 이벤트를 수신하고 필드를 삽입하고 개체 ID를 현재 시간으로 업데이트하여 고유 키를 제공하는 CoffeeScript가 있습니다.
jQuery ->
$('form').on 'click', '.add_fields', (event) ->
time = new Date().getTime()
regexp = new RegExp($(this).data('id'), 'g')
$(this).before($(this).data('fields').replace(regexp, time))
event.preventDefault()
이 코드는 유료 구독이 필요한 이 RailsCasts Pro 에피소드 에서 가져온 것입니다 . 그러나 GitHub에서 무료로 사용할 수있는 전체 작동 예제 가 있습니다 .
업데이트 :child_index
자리 표시자를 삽입하는 것이 항상 필요한 것은 아니라는 점을 지적하고 싶습니다 . JavaScript를 사용하여 새 레코드를 동적으로 삽입하지 않으려면 미리 빌드 할 수 있습니다.
def new
@project = Project.new
3.times { @project.items.build }
end
<%= f.fields_for :items do |builder| %>
Rails는 새 레코드에 대한 인덱스를 자동으로 삽입하므로 제대로 작동합니다.
그래서 가장 자주 본 솔루션이 만족스럽지 않았습니다. 서버 나 클라이언트 측 JS에서 새 요소에 대한 의사 인덱스를 생성하는 것이 었습니다. 특히 Rails / Rack이 []
인덱스로 모두 빈 괄호 ( )를 사용하는 한 항목 목록을 완벽하게 구문 분석 할 수 있다는 사실을 감안할 때 이것은 kludge처럼 느껴집니다 . 다음은 내가 작성한 코드의 근사치입니다.
# note that this is NOT f.fields_for.
fields_for 'parent[children_attributes][]', child, index: nil do |f|
f.label :name
f.text_field :name
# ...
end
옵션 []
과 함께 필드 이름 접두사를으로 끝내면 index: nil
Rails 인덱스 생성이 비활성화되므로 지속되는 객체를 제공하려고합니다. 이 스 니펫은 새 개체와 저장된 개체 모두에서 작동합니다. 결과 양식 매개 변수 []
는 일관되게를 사용하기 때문에 에서 배열로 구문 분석됩니다 params
.
params[:parent][:children_attributes] # => [{"name" => "..."}, {...}]
The Parent#children_attributes=
method generated by accepts_nested_attributes_for :children
deals with this array just fine, updating changed records, adding new ones (ones lacking an "id"
key), and removing the ones with the "_destroy"
key set.
I'm still bothered that Rails makes this so difficult, and that I had to revert to a hardcoded field name prefix string instead of using e.g. f.fields_for :children, index: nil
. For the record, even doing the following:
f.fields_for :children, index: nil, child_index: nil do |f| ...
...fails to disable field index generation.
I'm considering writing a Rails patch to make this easier, but I don't know if enough people care or if it would even be accepted.
EDIT: User @Macario has clued me in to why Rails prefers explicit indices in field names: once you get into three layers of nested models, there needs to be a way to discriminate which second-level model a third-level attribute belongs to.
The common solution is to add a placeholder into [], and replace it with a unique number on inserting the snippet to the form. Timestamp works most of the time.
Maybe you should just cheat. Put the new records in a different faux attribute that is a decorator for the actual one.
parent[children_attributes][0][fieldname]
parent[new_children_attributes][][fieldname]
It's not pretty, but it should work. It might take some extra effort to support round-trips to the form for validation errors.
I've came across this user case in all my last proyects, and I expect this to continue, as julian7 pointed, it is necesary to provide a unique id inside the []. In my opinion this is better done via js. I've been dragging and improving a jquery plugin for dealing with this situations. It works with existing records and for adding new records but expects a certain markup and it degrades gracefully, heres the code and an example:
https://gist.github.com/3096634
Caveats for using the plugin:
The fields_for call should be wrapped in a
<fieldset>
with data-association attribute equal to the pluralized name of the model, and a class 'nested_models'.an object should be built in the view just before calling fields_for.
the object fields perse should be wrapped in a
<fieldset>
with class "new" but only if the record is new (cant remember if I removed this requirement).A checkbox for the '_destroy' attribute inside a label must exist, the plugin will use the label text to create a destroy link.
A link with class 'add_record' should exist within the fieldset.nested_models but outside the fieldset enclosing the model fields.
Appart from this nuisances its been working wonders for me.
After checking the gist this requirements must be clearer. Please let me know if you improve on the code or if you use it :).
BTW, I was inspired by Ryan Bates first nested models screencast.
long post deleted
Ryan has an episode on this: http://railscasts.com/episodes/196-nested-model-form-revised
It looks like you need to generate the unique index manually. Ryan uses the object_id
for this.
I think you can make it work by including the id of the record as a hidden field
There is a gem called cocoon for doing this, I would go for a leaner mor DIY aproach but it was specifically built for this cases.
ReferenceURL : https://stackoverflow.com/questions/11445831/how-to-submit-multiple-new-items-via-rails-3-2-mass-assignment
'IT박스' 카테고리의 다른 글
람다를 블록으로 전달 (0) | 2020.12.25 |
---|---|
Entity Framework 대 저장 프로 시저-성능 측정 (0) | 2020.12.25 |
symfony2에서 엔티티를 삭제하려면 어떻게해야합니까? (0) | 2020.12.25 |
.NET Core 2.0으로 업그레이드 : PackageTargetFallback 및 AssetTargetFallback은 함께 사용할 수 없습니다. (0) | 2020.12.24 |
jQuery 또는 다른 라이브러리를 사용하는 Apple Cover-flow 효과? (0) | 2020.12.24 |