0

我已经进行了迁移以引入新的has_many关联has many :through。一个“标准”通过“layers_assoc”有 _many 个“层”。新功能在现有标准上运行良好,但创建新标准时,不会创建新层或 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>

根据标准保存:

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 约定,我花了几天时间才弄明白。创建操作既初始化对象又将对象保存到数据库中新操作只是初始化对象,然后调用.save将其提交到数据库。因此,在标准控制器上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 回答