我已经开始迁移,以引入新的has_many
和has many :through
关联。 “标准”通过“layers_assoc”具有_many“层”。新功能在现有标准上运行良好,但创建新标准,不会创建新图层或layer_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表中。
这是模特。标准.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.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)
这真是令人困惑。
答案 0 :(得分: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
将其提交给数据库。因此,在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,则不要将其包含在表单中,{{{}调用1}}并且创建新标准将无效。
希望能帮助别人!