0

我有一個叫做Option的模型,它具有自引用關聯。一個選項可以有許多子選項,子選項可以有一個父選項。我也使用cocoon gem的嵌套屬性在form_for選項上創建多個子選項。在表單上創建選項時,我可以動態創建子選項。Rails自引用屬性繼承

的意見/選項/ _form.html.erb:

<%= form_for @option do |f| %> 

    <p> 
    <%= f.label :name %><br> 
    <%= f.text_field :name %><br> 
    <%= f.label :activity %><br> 
    <%= f.select :activity_id, options_for_select(activity_array, @option.activity_id)%><br> 
    </p> 

    <div> 
    <div id="suboptions"> 
     <%= f.fields_for :suboptions do |suboption| %> 
     <%= render 'suboption_fields', f: suboption %> 
     <% end %> 

     <div class="links"> 
     <%= link_to_add_association 'add suboption', f, :suboptions %> 
     </div> 
    </div> 
    </div> 

    <p> 
    <%= f.submit "Send" %> 
    </p> 
<% end %> 

模型/ option.rb:

class Option < ApplicationRecord 
    belongs_to :activity 
    has_many :option_students 
    has_many :students, through: :option_students 
    has_many :suboptions, class_name: "Option", foreign_key: "option_id" 
    belongs_to :parent, class_name: "Option", optional: true, foreign_key: "option_id" 
    accepts_nested_attributes_for :suboptions, allow_destroy: true, 
    reject_if: ->(attrs) { attrs['name'].blank? } 

    validates :name, presence: true 

    after_initialize :set_defaults 
    before_update :set_defaults 


    def set_defaults 
     self.suboptions.each do |sbp| 
     sbp.activity_id = self.activity_id 
     end 
    end 

end 

PARAMS:

def option_params 
    params.require(:option).permit(:name, :activity_id, :students_ids => [], suboptions_attributes: [:id, :name, activity_id, :_destroy]) 
    end 

我想,每個子選項繼承來自父級的activity_id屬性,用於創建和更新。我通過在模型上使用set_defaults方法嘗試了這種方式,並且它爲新的嵌套子選項提供了一個新選項,並且它還更新了子選項的activity_id,如果我更新父級的activity_id。但是,如果在更新時創建另一個子選項,它不會將父項的屬性傳遞給新的子選項。

回答

3

您可以使用before_validation回調。例如,

測試代碼

class Location < ApplicationRecord 
    has_many :children, class_name: 'Location', foreign_key: 'parent_id' 
    accepts_nested_attributes_for :children 
    before_validation :initialize_children 

    attr_accessor :activity 

    def initialize_children 
    children.each { |c| c.activity_id = self.activity_id } 
    end 
end 

Rails的控制檯

irb(main):002:0> Location.create({name: "L10", activity_id: 200, :children_attributes => [{name: "L12"}]}) 
    (0.1ms) begin transaction 
    SQL (1.1ms) INSERT INTO "locations" ("name", "activity_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["name", "L10"], ["activity_id", 200], ["created_at", 2017-01-11 04:07:26 UTC], ["updated_at", 2017-01-11 04:07:26 UTC]] 
    SQL (0.1ms) INSERT INTO "locations" ("name", "parent_id", "activity_id", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?) [["name", "L12"], ["parent_id", "1"], ["activity_id", 200], ["created_at", 2017-01-11 04:07:26 UTC], ["updated_at", 2017-01-11 04:07:26 UTC]] 
    (3.7ms) commit transaction 
=> #<Location id: 1, name: "L10", parent_id: nil, activity_id: 200, created_at: "2017-01-11 04:07:26", updated_at: "2017-01-11 04:07:26"> 
irb(main):003:0> Location.all 
    Location Load (0.2ms) SELECT "locations".* FROM "locations" 
=> #<ActiveRecord::Relation [#<Location id: 1, name: "L10", parent_id: nil, activity_id: 200, created_at: "2017-01-11 04:07:26", updated_at: "2017-01-11 04:07:26">, #<Location id: 2, name: "L12", parent_id: "1", activity_id: 200, created_at: "2017-01-11 04:07:26", updated_at: "2017-01-11 04:07:26">]> 
irb(main):004:0> Location.last 
    Location Load (0.2ms) SELECT "locations".* FROM "locations" ORDER BY "locations"."id" DESC LIMIT ? [["LIMIT", 1]] 
=> #<Location id: 2, name: "L12", parent_id: "1", activity_id: 200, created_at: "2017-01-11 04:07:26", updated_at: "2017-01-11 04:07:26"> 
+0

但是我想如果我更新的價值實在不行,是不是? –

+0

已更新答案。查看。 – fossil

+0

現在它適用於以前的孩子,但如果我添加一個新孩子,它不起作用。我做這樣的: 'after_initialize:set_defaults before_update:set_defaults 高清set_defaults self.suboptions.each做|伴侶| sbp.activity_id = self.activity_id end ' –