2013-05-09 58 views
0

我已经运行迁移以引入新的has_manyhas many :through关联。 “标准”通过“layers_assoc”具有_many“图层”。新功能可以在现有标准下正常工作,但创建新标准时不会创建新图层或图层_assocs。Rails has_many未在创建时填充

尽管创建了关联和具有默认值的迁移,但是在创建标准时是否必须创建关联的实例?

下面是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 

layers.rb:

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

layers_assoc.rb:

belongs_to :standard 
belongs_to :layer 

更新2: 我所有,但解决这个问题。 LayersAssocs会以默认值创建,但我没有为标准建立默认图层关联。我已经在新方法中将这些默认关联写入了before_filter,它工作得很好。但是,尽管保存了标准layer_id,但保存标准时,层ID将消失。

例LayersAssoc后LayersAssoc.new循环:

#<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) 

这确实是混杂。

+0

请提供您用于创建的代码。 – wintermeyer 2013-05-09 20:15:54

+0

已添加。我会在标准模型创建动作中插入'LayersAssoc.create'模块,但这样做不必要。 – Archonic 2013-05-09 21:07:54

+0

我认为它与标准,图层或layers_assoc模型中某处缺少'attr_writter'有关。 – Archonic 2013-05-09 22:21:56

回答

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标准控制器新动作:

<%= 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> 
... 

注意隐藏:

@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对象initilized,你可以在新的页面上显示的形式为他们字段为:layer_id提交给标准模型创建的唯一东西是表单的值。如果你在before过滤器中初始化layer_id,那么不要将它包含在表单中,当调用standard.save时它将为零,并且创建一个新的标准将不起作用。

希望能帮助别人!