1

現在、複数の結合テーブルを使用して、アーティストがアルバムにどのように関連しているかを示すアルバム/アーティスト データベースがあります。彼らは、作曲家、アレンジャー、またはパフォーマーとしてリストできます。あれは:

class Artist < ActiveRecord::Base
...
has_and_belongs_to_many :albumbycomposers, :class_name => "Album", :join_table => "albums_composers"
has_and_belongs_to_many :albumbyarrangers, :class_name => "Album", :join_table => "albums_arrangers"
has_and_belongs_to_many :albumbyperformers, :class_name => "Album", :join_table => "albums_performers"
...
end

class Album < ActiveRecord::Base
has_and_belongs_to_many :composers, :class_name => "Artist", :join_table => "albums_composers"
has_and_belongs_to_many :arrangers, :class_name => "Artist", :join_table => "albums_arrangers"
has_and_belongs_to_many :performers, :class_name => "Artist", :join_table => "albums_performers"
... 
end

このコードは、データベース内の既存のアーティストを検索し、関連付けを作成するために使用されます。アーティストが存在しない場合は、.build メソッドを使用してアーティストを作成します。

class AlbumsController < ApplicationController
  ...
  def create
    @album = Album.new(params[:album])

    params["Composer Names"].each do |each|
      if each.empty? == false
        @exists = Artist.find_by_name(each)
        if @exists.nil? == true
          @album.composers.build(:name => each)
        else
          @album.composers << Artist.find_by_name(each)
        end
      end
    end

    params["Arranger Names"].each do |each|
      if each.empty? == false
        @exists = Artist.find_by_name(each)
        if @exists.nil? == true
          @album.arrangers.build(:name => each)
        else
          @album.arrangers << Artist.find_by_name(each)
        end
      end
    end
    ...
  end
  ...
end

私が遭遇する問題は、作曲家と編曲家の両方として新しいアーティストを入力しようとしたときに発生します。たとえば、これを投稿リクエストとして送信するとします。

Parameters: {"Name"=>["New Album"],
             "Performer Names"=>["New Artist"], 
             "Composer Names"=>["New Artist"], 
             "Arranger Names"=>["New Artist"], 
             ...
            }

composer 引数が最初にあるため、Rails はそれらを適切に解釈します (あたかもアーティストが存在しないかのように)。アレンジャーとパフォーマーの引数も、アーティストが存在しないかのように解釈されます。次に、Rails がデータベースにデータを挿入し始めます。最初にアルバムが作成され、albums テーブルに挿入されます。次に、"New Artist" が作成され、album_composer に挿入されます (.build メソッドに従って)。

ただし、アレンジャーとパフォーマーの引数については、アーティストが作成されたため、build メソッドを使用できなくなり、コードが正しく実行されません。

この特定のケースでは、アレンジャーとパフォーマーの引数行でプッシュ メソッド (別名 <<) を使用して回避しようとしましたが、作曲家の引数によってアーティストが作成されるのを待たずに即座に起動するため、それは機能しません。 「アーティストが見つかりません」というエラーが表示されます。参考のため:

collection<<(object, …)
Adds one or more objects to the collection by creating associations in the join table (collection.push and collection.concat are aliases to this method). 
Note that this operation instantly fires update sql without waiting for the save or update call on the parent object.

これを処理する適切な方法は何ですか?

4

1 に答える 1

0

最初にコードを使用して、各アーティストをデータベースに個別に追加することで問題を解決しました。

@artists = params["Composer Names"] | params["Arranger Names"] | params["Performer Names"]
@artists.each do |artist|
  if artist.empty? == false
    @exists = Artist.find_by_name(artist)
    if @exists.nil?
      @artist = Artist.new(:name => artist)
      @artist.save
    end
  end
end

次のようなコードを使用して、プッシュ メソッドを使用し、各アーティストを適切な結合テーブルに追加できます。

params["Composer Names"].each do |each|
  if each.empty? == false
    @album.composers << Artist.find_by_name(each)
  end
end

だからそれだ!

于 2012-07-04T03:01:59.970 に答える