【问题标题】:Creating nested records on create with Rails使用 Rails 创建嵌套记录
【发布时间】:2016-01-18 21:41:12
【问题描述】:

我有一个项目模型,用于在创建时在特定项目中自动生成部门。这包含在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

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

【问题讨论】:

  • 那么,项目有_many职位,部门有_many职位?
  • 我把那条线放在那里是为了尝试这样做。我想正确的方法是项目has_many: departments 和部门has_many: positions
  • 是的,听起来不错。然后项目有_很多职位,通过:部门,好玩好玩!

标签: html ruby-on-rails ruby-on-rails-3 associations rails-activerecord


【解决方案1】:

有两种方式:

#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

【讨论】:

  • 我收到错误syntax error, unexpected tLABEL, expecting keyword_end dept.positions &lt;&lt; Position.new position: "Test Art" ^。我的模特是dept.positions &lt;&lt; Position.new position: "Test Pos"
  • 你可能需要用括号括起来:dept.positions &lt;&lt; Position.new(position: "Test Art")
【解决方案2】:

如果我正确理解您的问题,您可能会在您的部门模型中执行以下操作:

after_create { self.positions.create! }

虽然这可能是一个有问题的方法。使用 ActiveRecord 回调(这就是我们提供 after_create 的原因)创建这样的记录会使您的整个应用程序变得非常脆弱。例如,如果您这样做,您将永远无法创建没有相关职位的部门。也许有一天你需要这样做。

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

【讨论】:

  • 我确实允许用户单独创建部门和职位,我只是希望在用户创建项目时预先打包几个部门和各自的职位。
  • 然后,我要做的就是首先在相关的控制器方法中编写代码,在你的情况下可能是 users_controller#create。然后我可能会将其提取到服务对象或其他东西中。但我不会在模型中这样做。
  • 在你的控制器中,你可以像 `department = projects.departments.create;部门.职位.创建。您可以在控制器的创建操作中执行此操作。
【解决方案3】:

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

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”只是为了说明,您可以将&lt;&lt; 符号用于任何部门或项目实例。

再看一遍,它似乎非常适合多态关联。

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

可能有更合适的方式来为您的应用命名,但这是大体思路。

【讨论】:

  • 很抱歉,我无法看到它是如何工作的。我收到一条错误消息,说 &lt;&lt; 是一个未定义的方法。
  • @project.departments << @position)
  • 啊,我的错.. 遗漏了.positions - 已修复
  • 此方法似乎与部门无关。我的职位模型中有 department_idproject_idposition_title 的列。 .first 也引用了模型中的第一行,在我的例子中,我试图为每个项目创建不同的东西。我的 .first 记录是有史以来创建的第一个记录,我需要当前正在制作的项目中的第一个记录。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多