同时使用has_one和has_many关联

时间:2016-06-22 15:03:57

标签: ruby-on-rails ruby-on-rails-4 associations

我正在尝试在一个模型中使用has_one和has_many方法。任务流可以有许多任务,但它也只有一个默认任务。

我正在尝试在任务流表中创建一个包含任务ID的列。但是,当我尝试设置默认任务时,它不起作用。

class Taskflow < ActiveRecord::Base
    has_many :tasks
    has_one :default_task, :class_name => 'Task'

class Task < ActiveRecord::Base
    belongs_to :taskflow

我在数据库中播种然后在rails控制台中尝试将任务分配为任务流default_task:

taskflow1 = Taskflow.first
task1 = Task.first
taskflow1.default_task = task1

这不适用于任务流default_task值剩余'nil'。实现理想行为的正确方法是什么?

非常感谢任何帮助。

修改

迁移文件是:

class CreateTaskflows < ActiveRecord::Migration
  def change
    create_table :taskflows do |t|
      t.string :title
      t.string :description
      t.references :default_task
      t.timestamps null: false
    end
  end
end

class CreateTasks < ActiveRecord::Migration
  def change
    create_table :tasks do |t|
      t.string :task_type
      t.text :help
      t.text :data
      t.belongs_to :taskflow
      t.timestamps null: false
    end
  end
end

4 个答案:

答案 0 :(得分:5)

我会以不同的方式实施它。我将在Task模型上创建一个布尔字段default_task。而Taskflow将具有以下has_one和has_many关联:

class Taskflow < ActiveRecord::Base
    has_many :tasks
    has_one :default_task, class_name: 'Task', condition: proc{"tasks.default_task = true"}

从语义上讲,Taskflow应该有许多任务,并且在这些任务中有一个默认任务。而且我认为任务流属于默认任务听起来有点人为。

您还可以添加一项功能,以便将单个任务持续维护为默认任务(位设置为true,更多详细信息here),或者在创建任务流时创建默认任务。这一切都取决于您的要求。

AND,如果您仍希望将default_task_id列置于Taskflow模型上并使用has_one关联,则可以执行以下操作:

class Taskflow < ActiveRecord::Base
    has_many :tasks
    has_one :default_task, class_name: "Task", primary_key: "default_task_id", foreign_key: "id"

答案 1 :(得分:1)

has_one 用于指定与另一个类的一对一关联。仅当其他类包含外键时才应使用此方法。

在您的情况下,您应该使用 belongs_to 作为default_task引用在TaskFlow模型中(在迁移中)。

TaskFlow模型有两个关系:

  • TaskFlow有很多任务
  • TaskFlow有一个特定任务是默认任务。

class Taskflow < ActiveRecord::Base has_many :tasks belongs_to :default_task, :class_name => 'Task'

class Task < ActiveRecord::Base belongs_to :taskflow

你拥有它的方式,Rails不知道哪个任务是默认任务。

答案 2 :(得分:1)

这里的人对于belongs_to或如何破解has_one是正确的。我知道belongs_to在这种情况下感觉不对,但如果你在表中使用“引用”,你通常总是想使用belongs_to。所以我假设将任务本身的默认任务标记为默认任务 - 但如果它们可以是不同task_flows的一部分,其中不同的任务可能是默认任务 - 那么当然这是不可能的。

这里已经提到过的人的另一个选择是:你可以在has_many:tasks关系中添加一个范围。像这样:

has_many :tasks do
  def default
    joins(:task_flow).where('tasks.id = task_flows.default_task_id').first
  end
end

然后你可以要求

@task_flow.tasks.default

答案 3 :(得分:0)

我让这个工作。 <{1}}取代has_one,而模型中需要belongs_to

class Taskflow < ActiveRecord::Base
    has_many :tasks
    belongs_to :default_task, :class_name => 'Task'

class Task < ActiveRecord::Base
    belongs_to :taskflow

我认为与has_one的关系与我的假设有相反的关系。 http://guides.rubyonrails.org/association_basics.html#the-has-one-association