3

我正在使用Rails的accep_nested_attributes_for方法取得了巨大的成功,但是如何在不存在記錄的情況下創建新記錄呢?accpets_nested_attributes_for,HABTM和find_or_create

我發現這篇文章,accepts_nested_attributes_for with find_or_create?,但它似乎並不適用於我的情況。

我在包和許可證之間有多對多的關係。例如,應該只有一個許可證實例:我不應該有兩個許可證命名爲「Awesome」

所需的功能是當我創建一個包時,將許可證名稱作爲屬性,如果該名稱尚不存在或創建現有許可證(使用提供的名稱)與包之間的關聯,則創建一個新許可證。

這裏是什麼我的模型是這樣的:

class Package < ActiveRecord::Base 
    has_and_belongs_to_many :licenses, :autosave => true 
    accepts_nested_attributes_for :licenses 
end 

class License < ActiveRecord::Base 
    attr_accessible :name 
    has_and_belongs_to_many :packages 
    validates :name, :presence => true 
end 

回答

0

我有一個類似的問題,並用回調鉤子解決它。在我的情況下,我有一個狀態模型和一個人模型。我想讓用戶在狀態更新中標記多個人(Person),只需輸入一個名稱並創建一個新的Person(這些不會映射到Users,btw,它只是供私人使用),如果匹配的人不存在。

class Person < ActiveRecord::Base 
    has_and_belongs_to_many :statuses 
end 

Class Status < ActiveRecord::Base 
    has_and_belongs_to_many :people 
    accepts_nested_attributes_for :people 
    before_save :get_people 

    def get_people 
    self.people.map! do |person| 
     Person.find_or_create_by_name(person.name) 
    end 
    end 
end 
+0

在我的情況下 'def get_people' 'self.people.map! do | person |' 'Person.find_or_create_by_name(person。名)' 'end' 'end' 沒有工作,但 '高清get_people' 'self.people = self.people.collect做|人|'' Person.find_or_create_by_name(person.name) ' 'end' 'end' 確實! – Muntasim

0

如果「名」真的是會被用來創建它,如果它不存在,那麼你可以做這個許可證的唯一屬性通過對Package類的回調和虛擬屬性:

class Package < ActiveRecord::Base 
    has_and_belongs_to_many :licenses, :autosave => true 
    before_create :set_license_from_name 
    attr_accessor :license_name  

    protected 

     def set_license_from_name 
     self.licenses << Licence.find_or_create_by_name(self.license_name) 
     end 

end 

然後,你可以可以只在licence_name通過作爲新的包裝對象的屬性,例如使用text_box:

<%= form_for @package do |f| %> 
    <%= f.text_field :license_name %> 
<% end %> 

雖然可能不是世界上最好的用戶界面。相反,您可能希望人們能夠從下拉框中選擇現有許可證,或輸入新許可證的名稱。有一種情況是accepts_nested_attributes_for有用:

class Package < ActiveRecord:Base 
    has_and_many :licenses 
    accepts_nested_attributes_for :licenses, :reject_if => :all_blank 
end 

class PackagesController < ApplicationController 

    def new 
     @package = Package.new 
     @package.licenses.build 
     @licenses = License.all 
    end 
end 

並在視圖:

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

    License: 
    <%= f.collection_select :license_id, @licenses, :id, :name, :include_blank => true %> 

    or create a new one: 
    <%= f.fields_for :licenses do |l| %> 
    <%= l.text_field :name %> 
    <% end %> 
<% end %> 

你必須做在控制器的create動作多一點的工作,得到這個工作,但它不應該太難。

+0

我正在使用<<方法通過腳本添加許可證。爲了測試模型,我有以下rspec腳本'describe「許可證」do 它「應該只創建一個許可證的單個實例」do @ package.licenses.create!(:name =>「TEST」) 數= License.all.count @ package.licenses.create!(:名稱=> 「TEST」) License.all.count.should ==算 結束 end'即使實施上述的腳本之後似乎仍然失敗。 –

+0

Roberto對此有何幫助?它似乎仍然不起作用。在許可級別有沒有辦法達到相同的邏輯,而不是程序包級別? –