2017-11-07 17 views
2

두 개가 아닌 하나의 레코드에 대해 다른 구조를 가지고 있습니다.이 필드를 제목으로 처리하기 위해 고심했습니다.여러 레코드가있는 SimpleForm의 Params 해시는

하나 이상의 필드 세트가있는 일괄 편집 페이지를 작성하기 위해 SimpleForm을 사용하고 있습니다. 빌드되었지만 아직 저장되지 않은 ActiveRecord 모델 모음의 각 레코드에 하나씩입니다.

내 양식은 다음과 같습니다

= simple_form_for :courses, method: :patch do |f| 
    - @courses.each do |course| 
    = field_set_tag do 
     = f.simple_fields_for 'courses[]', course do |c| 
     = c.input :title 
     .row 
      .medium-6.columns 
      = c.input :start_date, as: :string, input_html: { class: 'input-datepicker' } 
      .medium-6.columns 
      = c.input :end_date, as: :string, input_html: { class: 'input-datepicker' } 
    = f.submit 'Save', class: 'primary button' 

하나 개의 레코드에 대한 PARAMS 해시는 다음과 같습니다

: 두 개의 레코드 것은 다음과 같습니다 동안, 배열과

"courses"=>{"courses"=>[{"title"=>"Course Y", "start_date"=>"2017-09-26", "end_date"=>"2017-07-31"}]} 

"courses"=>{"courses"=>{"1"=>{"title"=>"Course X", "start_date"=>"2018-01-16", "end_date"=>"2018-07-30"}, "2"=>{"title"=>"Course Y", "start_date"=>"2017-09-26", "end_date"=>"2018-07-30"}}} 

문자열이있는 정수 키가있는 해시입니다.

강력한 매개 변수를 사용하려고하면이 문제가 발생합니다.

ActionController::Parameters 
    .new(courses: params[:courses][:courses].values) 
    .permit(courses: [:title, :start_date, :end_date]) 
    .require(:courses) 

그것은 param is missing or the value is empty: courses 위의 .require(:courses) 라인을 강조 실패 : 많은 해킹 후, 나는 하나가 제출 될 때 여러 기록을 위해 작동하지만 실패 코드의 조각으로 돌아가 셨습니다.

if params[:courses][:courses].is_a?(Array) 
    params[:courses][:courses] = { '1': params[:courses][:courses][0] } 
end 

하지만 그것을하는 간단한 방법이 있어야처럼 느낌 :

문제

는 여러 레코드 케이스 단일 기록 케이스를 조화하여 "해결"입니다.

이 유스 케이스의 양식을 작성하는 더 좋은 방법이 있습니까? 강력한 매개 변수가있는 트릭이 누락 되었습니까?

나는 rails 5.0.5simple_form 3.5.0을 사용하고 있습니다.

+0

어둠 속에서 약간의 발사가 있지만'= f.simple_fields_for '코스 []','do f | fsimple_fields_for : course do course | c |' 매번 동일한 유형의 매개 변수 해시가 발생할 수 있습니다. –

+0

"하지만 더 간단한 방법이 있어야한다고 생각합니다." - 예, 개별 작성/업데이트 요청을 보내려면 ajax를 사용하십시오. – max

+0

하지만'.require' 대신'.fetch'를 사용할 수는 있지만, 아직도 그다지 유지할 ​​수없는 엉망진창이 될 것입니다. – max

답변

0

그것은 f.simple_fields_for 'courses[]' ... 방법 가 제공 밝혀 양식이 기존의 레코드로 채워진 경우 ID를 필드화하고 코스 해시에 매핑되는 문자열 ID의 params 구조 만이 경우 사용됩니다. "신선한"레코드의 경우 ID가없고 코스 해시가 일반 배열로 배치됩니다.

이 코드는 이전 과정을 복사하고 날짜를 변경하는 과정에서 1 년에서 다른 기간으로 "롤 오버"하는 컨텍스트에서 실행되었습니다. 이것은 각 필드 세트가 원래 코스의 ID를 가짐을 의미합니다.

양식을 제출할 때 새 레코드가 만들어지고 새 특성으로 유효성이 검사되었으며 ID가없는이 새 레코드가 양식을 다시 채웠습니다. "한 과정 만 제출하면 문제가 발생합니다"라는 것은 테스트 시나리오의 결과물 인 붉은 청어였습니다.

가치가 있으므로 f.simple_fields_for 'courses[]' ...은 새 레코드에 대한 배열을 만들고 기존 레코드에 대한 특성에 해시 매핑 ID를 만듭니다.

1

"하지만 더 간단한 방법이 있어야한다고 생각합니다."

예, 개별 작성/업데이트 요청을 보내려면 ajax를 사용하십시오. 이는 사용자에게 투명하게 수행 될 수 있으며보다 간단한 코드와 훨씬 나은 사용자 경험을 제공합니다.

레일즈는 하나의 요청으로 여러 개의 하위 레코드와 상위 레코드를 생성/업데이트하는 데 사용할 수있는 fields_foraccepts_nested_attributes을 가지고 있습니다. 그러나 실제로는 레코드를 그룹화하는 연관성이 필요합니다. 심지어이 경우에도 유효성 검사와 관련하여 실제로 해킹되고 복잡해 질 수 있습니다.

당신은 당신이 각 레코드에 대해 별도의 양식을 가질 수 있도록이를 설정하려면 :

# courses/_form.haml.erb 
= simple_form_for course, remote: true, html: { 'data-type' => 'json', class: 'course_form'} do |f| 
    = c.input :title 
    .row 
    .medium-6.columns 
     = c.input :start_date, as: :string, input_html: { class: 'input-datepicker' } 
    .medium-6.columns 
     = c.input :end_date, as: :string, input_html: { class: 'input-datepicker' } 
    = f.submit 'Save', class: 'primary button' 

대신의 js.erb 템플릿 우리를 사용하여 : 정말 폼에 아무것도 없다

- courses.each do |c| 
    = render partial: 'courses/_form', course: c 

'data-type' => 'json'을 사용하고 올바른 형식을 쉽게 타겟팅 할 수 있도록 자체 처리기를 작성하십시오.

$(document).on('ajax:success', '.course_form', function(event, xhr, status){ 
    var $form = $(this); 
    alert('Course created'); 
    if (this.method.post) { 
    // changes form to update instead. 
    this.method = 'patch'; 
    this.action = xhr.getResponseHeader('Location'); 
    } 
}); 

$(document).on('ajax:error', '.course_form', function(event, xhr, status){ 
    var $form = $(this); 
    // @todo display errors 
}); 
컨트롤러 만들기 10

은 매우 정직 :

class CoursesController 
    def create 
    @course = Course.new(course_params) 
    respond_to do |format| 
     if @course.save(course_params) 
     format.json { head :created, location: @course } 
     else 
     format.json do 
      render json: { 
      errors: @course.errors.full_messages 
      } 
     end 
     end 
    end 
    end 

    def update 
    @course = Course.find(params[:id]) 
    respond_to do |format| 
     if @course.update(course_params) 
     format.json { head :ok } 
     else 
     render json: { 
      errors: @course.errors.full_messages 
     } 
     end 
    end 
    end 
end 
+0

이것은 좋은 접근 방식입니다, 감사합니다. 나는이 작품을 위해이 작품을 사용하지 않을 것이라고 생각하지만, 앞으로는 분명히 유용 할 것이다. 장소에서 수정 작업을 수행하는 좋은 방법이 될 것입니다! – Jacob

1

것은 양식을 유지이 강한 PARAMS을 변경 PARAMS는 인덱스 키없이해야이 코드

params.require(:courses).permit(
    courses: [ 
    :id, 
    :title, 
    :start_date, 
    :end_date 
    ] 
) 

, @courses은 배열입니다 :

# CoursesController 
def new 
    @courses = [] 
    # creating 3 items for example 
    3.times do 
    @courses << Course.new 
    end 
end 

def create 
    errors = false 
    @courses= [] 
    # keep courses in the array for showing errors 
    courses_params[:courses].each do |params| 
    course = Course.new(params) 
    @courses << course 
    unless course.valid? 
     errors = true 
    end 
    end 
    if errors 
    render :new 
    else 
    # if no errors save and redirect 
    @courses.each(&:save) 
    redirect_to courses_path, notice: 'courses created' 
    end 
end 
+0

슬프게도 강력한 매개 변수 코드는 해시 배열의 경우에만 작동합니다. 속성 해시에 대한 ID 해시의 경우 유효하지 않습니다. 어쨌든 고마워! – Jacob