使用 Rails 创建嵌套记录

Creating nested records on create with Rails

我有一个项目模型,用于在创建特定项目时自动生成部门。这包含在 projects 模型中:

class Project < ActiveRecord::Base
    attr_accessible :title, :departments_attributes, :positions_attributes, :id
    belongs_to :user
    has_many :departments
    has_many :positions
    validates :title, presence: true

    before_create :set_departments
    accepts_nested_attributes_for :departments
    accepts_nested_attributes_for :positions

    private
       def set_departments
            self.departments.build department: "Test Dept", production_id: self.id

       end

end

每个部门都有很多职位。我也在努力为部门创造职位。我如何将新职位与此模型中的部门相关联?

您可以通过以下方式添加新职位:

Project.first.positions << Position.create(:foo => 'foo', :bar => 'bar')

position = Position.create(:foo => 'foo', :bar => 'bar')
Department.first.positions << position
Project.first.positions << position

显然“.first”只是为了说明,您可以对任何部门或项目实例使用 << 符号。

再看看这个,它似乎非常适合多态关联。

class Position < ActiveRecord::Base
  belongs_to :positioned, polymorphic: true
end

class Project < ActiveRecord::Base
  has_many :positions, as: :positioned
end 

class Department < ActiveRecord::Base
  has_many :positions, as: :positioned
end

在您的迁移中:

  create_table :positions do |t|
    ...
    t.integer :positioned_id
    t.string  :positioned_type
    ...
  end

可能有更合适的方式为您的应用命名,但这是一般的想法。

如果我对你的问题的理解正确,你可能会在你的 Department 模型中做这样的事情:

after_create { self.positions.create! }

尽管这可能是一种有问题的方法。使用 ActiveRecord 回调(这给了我们 after_create)创建这样的记录会使您的整个应用程序非常脆弱。例如,如果您这样做,您将永远无法创建一个没有关联职位的部门。也许有一天你需要这样做。

因此,即使这不是您问题的确切答案,我还是建议查看在服务对象中或至少在控制器代码中创建这些关联模型。

有两种方法:

#app/models/project.rb
class Project < ActiveRecord::Base
   has_many :departments
   accepts_nested_attributes_for :departments

   before_create :set_department

   private

   def set_department
      self.departments.build department: "Test"
   end
end

#app/models/department.rb
class Department < ActiveRecord::Base
    has_many :positions
    accepts_nested_attributes_for :positions

    before_create :set_positions

    private

    def set_positions
       self.positions.build x: y
    end
end

...或...

#app/models/project.rb
class Project < ActiveRecord::Base
   has_many :departments
   accepts_nested_attributes_for :departments, :projects

   before_create :set_departments

   private

   def set_departments
      dpt = self.departments.build department: "Test"
      dpt.positions << Position.new position: "Admin"
      dpt.positions << Position.new position: "Tester"
   end
end

--

您还可以在一行中声明多个嵌套属性:

accepts_nested_attributes_for :departments, :positions