0

has_many新しいand関連付けを導入するために移行を実行しましたhas many :through。「標準」には、「layers_assoc」までの_多くの「レイヤー」があります。新しい機能は既存の標準で正常に動作しますが、新しい標準を作成しても、新しいレイヤーまたはlayers_assocsは作成されません。

デフォルトを持つ関連付けと移行を作成しても、標準の作成時に関連付けのインスタンスを作成する必要がありますか?

これは、layers_assocs テーブルの移行です。

class CreateLayersAssocs < ActiveRecord::Migration
  def up
    create_table :layers_assocs do |t|
      t.timestamps
      t.integer :layer_id, :null => false      # has_many
      t.integer :standard_id, :null => false   # has_many
      t.boolean :visible, :default => true
    end

    add_index :layers_assocs, :layer_id
    add_index :layers_assocs, :standard_id

    LayersAssoc.reset_column_information

    puts "== Populating LayersAssoc table ============================"
    Standard.all.each do |standard|
      Layer.all.each do |layer|
        begin
          LayersAssoc.create!(
            standard_id: standard.id, 
            layer_id: layer.id, 
            visible: true
          )
        rescue
          puts "== Failed to populate standard_id: #{standard.id} with layer_id: #{layer.id} "
          continue
        end
      end
    end
    puts "== Finished Populating LayersAssoc table ==================="
  end

  def down
    drop_table :layers_assocs
  end
end

移行が本番環境でうまくいかない場合に役立つ追加のものがいくつかあります。標準を作成した後、それは言うundefined method 'visible'. 次に、データベースを確認すると、最新の標準がlayers_assocsテーブルにないことがわかります。

これがモデルです。standard.rb の重要な部分:

has_many :layers_assocs
has_many :layers, :through => :layers_assocs
accepts_nested_attributes_for :layers_assocs

レイヤー.rb:

has_many :layers_assocs
has_many :standards, :through => :layers_assocs

層_assoc.rb:

belongs_to :standard
belongs_to :layer

更新 2: この問題はほとんど解決しました。LayersAssocs はデフォルトで問題なく作成されますが、標準のデフォルトのレイヤ アソシエーションを確立するものは何もありませんでした。これらのデフォルトの関連付けをbefore_filter新しいメソッドに書き込んだところ、問題なく動作しました。ただし、 が設定されているにもかかわらずlayer_id、規格を保存すると画層 ID が表示されなくなります。

LayersAssoc.new ループ後の LayersAssoc の例:

#<LayersAssoc id: nil, created_at: nil, updated_at: nil, layer_id: 1, standard_id: nil, visible_authors: true, visible_reviewers: true>

standard.save 時:

Mysql2::Error: Column 'layer_id' cannot be null: INSERT INTO `layers_assocs` (`created_at`, `layer_id`, `standard_id`, `updated_at`, `visible_authors`, `visible_reviewers`) VALUES ('2013-05-13 21:49:36', NULL, 112, '2013-05-13 21:49:36', 1, 1)

これは本当に混乱しています。

4

1 に答える 1

0

LayersAssocs オブジェクトはデフォルトで問題なく作成できましたが、(レイヤの関連付けを通じて) デフォルトのレイヤを確立するものは何もありませんでした。移行では、このコードによって既存の標準のデフォルトが確立されました。

Standard.all.each do |standard|
  Layer.all.each do |layer|
    begin
      LayersAssoc.create!(
        standard_id: standard.id, 
        layer_id: layer.id, 
        visible: true
      )
    rescue
      puts "== Failed to populate standard_id: #{standard.id} with layer_id: #{layer.id} "
      continue
    end
  end

そのデフォルトは、標準コントローラーの新しいアクションに変換する必要がありました。しかし、私はあらゆる種類の Rails 規則を見逃していました。それを理解するのに数日かかりました。create アクションは、オブジェクトの初期化とデータベースへの保存の両方を行います。新しいアクションは、オブジェクトを初期化してから呼び出すだけで、.saveそれを DB にコミットします。したがって、before_filter新しいアクションの標準コントローラでは次のようになります。

@standard = Standard.new
@organization = Organization.find(params[:organization_id])
@standard.organization = @organization

# Create default layers associations
@default_layers = []
for i in 1..5 do
  @default_layers << LayersAssoc.new(layer_id: i)
end
@standard.layers_assocs = @default_layers

これらのLayerAssocsオブジェクトが初期化されると、新しいページにそれらのフォームを表示できます。

<%= form_for(@standard) do |form| %>
  ...
 <%= form.label t('standard.layers') %>
 <table class="table table-striped span4">
   <thead>
     <tr>
       <td><strong><%= t('standard.layer') %></strong></td>
       <td><strong><%= t('type.authors') %></strong></td>
       <td><strong><%= t('type.reviewers') %></strong></td>
     </tr>
   </thead>
   <tbody>
     <% @standard.layers_assocs.each do |assoc| %>
       <%= form.fields_for :layers_assocs, assoc do |layer_field| %>
         <tr>
           <%= layer_field.hidden_field :layer_id, :value => assoc.layer_id %>
           <td><%= t(assoc.layer.name, :default => assoc.layer.name) %></td>
           <% if assoc.layer_id == 1 %>
             <td><%= layer_field.check_box :visible_authors, :disabled => true %></td>
             <td><%= layer_field.check_box :visible_reviewers, :disabled => true %></td>
           <% else %>
             <td><%= layer_field.check_box :visible_authors %></td>
             <td><%= layer_field.check_box :visible_reviewers %></td>
           <% end %>
         </tr>
       <% end %>
     <% end %>
   </tbody>
 </table>
 ...

の隠しフィールドに注意してください:layer_id作成のために標準モデルに送信されるのは、フォームの値だけです。before フィルターで layer_id を初期化し、それをフォームに含めない場合、standard.saveが呼び出されたときに nil になり、新しい標準の作成が機能しません。

それが誰かを助けることを願っています!

于 2013-05-16T16:18:24.163 に答える