2013-07-09 93 views
1

我建立一個武術相關的數據庫,目前我有以下協會成立:如何通過一種形式創建多個「has_many through」關聯?

  • 學生has_and_belongs_to_many:風格
  • 風格的has_many:居
  • 學生的has_many:行列,通過:分級(反之亦然)

我產生如下形式,根據學生的風格:

grading form

所以標題由Style模型(太極,空手道......)產生的,那麼他們的排名列表如下(從Rank模型中得到),以及「道場」和「日期」字段應該屬於一旦創建了Grading模型。

問題:我知道如何構建一個創建一個關聯(或一個關聯+它的子項)的表單,但是如何創建一個可以同時創建多個關聯的表單?

而且,這將是實現以下一個乾淨的方式:這是選中成爲協會

  • Dojo和日期必須填寫的勾選線成功保存
  • 如果

    1. 只有線一條線是不會破壞的,它會破壞以前創建的任何關聯

    這就是我目前實施的檢索正確記錄的方法:

    class GradingsController < ApplicationController 
        before_filter :authenticate_sensei! 
    
        def index 
        @student = Student.includes(:styles).find(params[:student_id]) 
        @ranks = Rank.for_student_styles(@student) 
        split_ranks_by_style 
        end 
    
        private 
    
        def split_ranks_by_style 
        @karate = @ranks.select_style("Karate") 
        @tai_chi = @ranks.select_style("Tai Chi") 
        @weaponry = @ranks.select_style("Weaponry") 
        end 
    end 
    
    # Rank model 
    def self.for_student_styles(student) 
        includes(:style).where("styles.id in (?)", student.styles.map(&:id)) 
    end 
    
    def self.select_style(style) 
        all.map { |r| r if r.style.name == style }.compact 
    end 
    
  • 回答

    1

    像這樣的複雜形式最好在主資源的createupdate操作中發起的服務對象中處理。這使您可以輕鬆找到之後的邏輯發生位置。在這種情況下,您看起來可以在您的GradingsController中啓動服務對象。我還喜歡格式化標記中的很多數據,以便在服務對象中更輕鬆地進行處理。這可以通過傳遞類似"grade[style]""grade[rank]"這樣的名稱來完成。這將格式化你的參數作爲一個方便的哈希:{grade: {style: "karate", rank: "3"}}。該哈希可以傳遞給你的服務對象進行解析。

    沒有真正抓住您的具體要求,充分的程度,讓我們放在一起的例子形式:

    <%= form_for :grading, url: gradings_path do |f| %> 
        <h1><%= @rank.name %></h1> 
        <%- @grades.each do |grade| %> 
        <div> 
         <%= hidden_field_tag "grade[#{grade.id}][id]", grade.id %> 
         <%= check_box_tag "grade[#{grade.id}][active]" %> 
         ... 
         <%= text_field_tag "grade[#{grade.id}][date]" %> 
        </div> 
        <%- end %> 
        <%= submit_tag %> 
    <%- end %> 
    

    有了這樣的形式,你會得到你的PARAMS進入控制器看起來像這樣:

    "grade"=>{ 
        "1"=>{"id"=>"1", "active"=>"1", "date"=>"2013-06-21"}, 
        "3"=>{"id"=>"3", "date"=>"2013-07-01"} 
    } 
    

    恰好格式化爲我們交給我們的服務對象。保持我們的控制器非常乾淨:

    class GradingsController < ApplicationController 
    
        def index 
        # ... 
        end 
    
        def create 
        builder = GradeBuilder.new(current_user, params['grade']) 
        if builder.run 
         redirect_to gradings_path 
        else 
         flash[:error] = 'Something went wrong!' # maybe even builder.error_message 
         render :action => :index 
        end 
        end 
    
    end 
    

    所以,現在我們只需要把自定義的邏輯到我們的建設者,我可能會建議只是在你的/lib目錄製作一個簡單的Ruby類。它可能是這個樣子:

    class GradeBuilder 
    
        attr_reader :data, :user 
    
        def self.initialize(user, params={}) 
        @user = user 
        @data = params.values.select{|param| param['active'].present? } 
        end 
    
        def run 
        grades = data.each{|entry| build_grade(entry)} 
        return false if grades.empty? 
        end 
    
        private 
    
        def build_grade(entry) 
        grade = Grade.find(entry['id']) 
        rank = grade.rankings.create(student_id: user, date: entry['date']) 
        end 
    
    end 
    

    有顯然需要更多的工作來傳遞你從表格所需要的具體數據,以及額外的邏輯在GradeBuilder處理邊緣情況,但是這會給你以可維護和可擴展的方式處理這個問題的框架。

    +0

    感謝您的回答,我結束了實現類似的事情,一旦我記得我可以格式化哈希。服務對象使得一切都變得更加清潔! –

    相關問題