3

私はRailsのaccepts_nested_attributes_forメソッドを使って大成功を収めていますが、レコードがすでに存在する場合、どうすれば新しいレコードを作成できますか?accpets_nested_attributes_for、HABTM、find_or_create

私はこの記事を見つけましたが、accepts_nested_attributes_for with find_or_create?ですが、私の場合はうまくいかないようです。

私はパッケージとライセンスの間に多対多の関係があります。テーブルにライセンスのインスタンスが1つだけ存在する必要があります。例えば、「素晴らしい」という2つのライセンスを持つべきではありません。

希望の機能は、ライセンス名を名前がまだ存在しない場合は新しいライセンスを作成するか、既存のライセンス(提供された名前)とパッケージの間に関連付けを作成します。 「名前」は本当にそれがまだ存在していなかった場合は、それを作成するために使用されるライセンスの唯一の属性である場合

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

私も同様の問題があり、コールバックフックで解決しました。私の状況では、私はStatusモデルとPersonモデルを持っています。私は、名前を入力して新しいPersonを作成するだけで、Status更新で複数の人物(Person)にタグ付けさせたいと思っていました(これらはユーザーにはマップされません、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(人。名) ' ' end' 'end' は働いたが ' defの をget_people' 'self.people = self.people.collect DOされていません|人|' ' 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 

次に、あなただけのtext_boxを使用して、新しいパッケージオブジェクトの属性としてlicence_nameに例えばを渡すことができできます

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

おそらく世界でも最高のUIではありません。代わりに、既存のライセンスをドロップダウンボックスから選択するか、新しいライセンスの名前を入力できるようにすることができます。 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 @ package.licenses.create!(:name => "TEST") 数= License.all.count @ package.licenses.create!:== end'でも、スクリプト上記を実施した後 エンドを数える(名前=> "TEST") License.all.count.shouldまだ失敗するようです。 –

+0

Robertoこれに関する助言?それはまだ動作していないようです。パッケージレベルではなく、ライセンスレベルで同じロジックへの道はありますか? –