使用 has_many 时如何创建关联模型的实例:通过关联

Posted

技术标签:

【中文标题】使用 has_many 时如何创建关联模型的实例:通过关联【英文标题】:How to create an instance of an associated model when using a has_many :through association 【发布时间】:2016-04-02 14:00:51 【问题描述】:

我有两个模型(称为 UserPlan),我使用 has_many :through 关联(称为 Participation)进行了关联。计划应该由用户创建,因此我想知道:

如何通过模型实例访问create方法User创建模型实例Plan和join模型实例Participation

目前我只是想让它在 Rails 控制台中工作,但我当然想在我的应用程序中使用该功能。我不使用 HABTM 关联,​​因为下一步是向关系添加属性。

我可以通过输入访问现有的计划实例

 > User.first.plans.all

进入 Rails 控制台。但是当我尝试任一时

> User.first.plan.new

> User.first.plans.new

> User.first.plan.create

> User.first.plans.create

我收到一个错误提示

NoMethodError: undefined method `plan' for #<User:

NoMethodError: undefined method `plans' for #<User:

额外信息: 对应型号:

class User < ActiveRecord::Base

  has_many :participations            #, :foreign_key => ":user_id"
  has_many :plans, :through => :participations
  accepts_nested_attributes_for :participations, :plans

end

class Plan < ActiveRecord::Base

  has_many :participations            #, :foreign_key => ":plan_id"
  has_many :users, :through => :participations
  accepts_nested_attributes_for :participations, :users

end

class Participation < ActiveRecord::Base
  belongs_to :user            #, inverse_of: :participations
  belongs_to :plan            #, inverse_of: :participations

  validates :user_id, presence: true
  validates :plan_id, presence: true

end

架构是:

  create_table "participations", force: :cascade do |t|
    t.integer  "user_id",    null: false
    t.integer  "plan_id",    null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  add_index "participations", ["plan_id"], name: "index_participations_on_plan_id", using: :btree
  add_index "participations", ["user_id"], name: "index_participations_on_user_id", using: :btree

  create_table "plans", force: :cascade do |t|
    t.text     "title"
    t.text     "description"
    t.text     "plan_type"
    t.datetime "start_date"
    t.datetime "end_date"
    t.integer  "parent_id"
    t.datetime "created_at",  null: false
    t.datetime "updated_at",  null: false
  end

  add_index "plans", ["parent_id"], name: "index_plans_on_parent_id", using: :btree

  create_table "users", force: :cascade do |t|
    t.string   "email",                  default: "", null: false
    t.string   "encrypted_password",     default: "", null: false
    t.string   "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.integer  "sign_in_count",          default: 0,  null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.inet     "current_sign_in_ip"
    t.inet     "last_sign_in_ip"
    t.datetime "created_at",                          null: false
    t.datetime "updated_at",                          null: false
    t.string   "username",                            null: false
  end

  add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
  add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
  add_index "users", ["username"], name: "index_users_on_username", unique: true, using: :btree

end

【问题讨论】:

在我看来是正确的,奇怪的是 User.first.plans.all 有效但 User.first.plans.create(some_attr: "foo") 无效。我认为值得一问你确定你使用的是rails 4.2吗? 我也想不通。但是rails -vbundle show rails 在终端返回Rails 4.2.2~/.rvm/gems/ruby-2.2.1/gems/rails-4.2.2 【参考方案1】:

今天早上我可以使用User.first.plans.newUser.first.plans.create 创建一个新的Plan 实例。我唯一的猜测是重新启动 rails 控制台可以解决问题。我很肯定在发布上述问题之前我已经这样做了。

@MilesStanfield:谢谢!由于您的评论,我仔细检查了所有内容。这样做后,我想再试一次。

【讨论】:

以上是关于使用 has_many 时如何创建关联模型的实例:通过关联的主要内容,如果未能解决你的问题,请参考以下文章

通过Rails中的关联使用has_many创建新模型时出现不允许的参数错误

如何通过关联为 has_many 定义工厂

如何通过关联在 has_many 中使用回调?

如何在父应用程序模型和挂载引擎模型之间设置has_many关联?

如何在同一模型中进行 has_many 和 has_one 关联?

如何在Rails 5中删除模型时删除模型的所有关联