繁体   English   中英

Rails具有许多直通关系-新保存和创建之间的区别

[英]Rails Has Many Through Relationship - Difference Between New-Save and Create

我检查了有关has_many through关系的Rails指南,但是对于has_many through在视图中的控制器中的效果,它们的文档很差。

型号:

class Project < ActiveRecord::Base
  has_many :twitter_memberships
  has_many :twitter_accounts, through: :twitter_memberships
end

class TwitterAccount < ActiveRecord::Base
  has_many :twitter_memberships
  has_many :projects, through: :twitter_memberships
end

class TwitterMembership < ActiveRecord::Base
  belongs_to :project
  belongs_to :twitter_account
end

路线:

resources :projects do
  resources :twitter_accounts
end

问题是,当我使用create方法时 ,会自动创建一个TwitterMembership对象,但是当我使用new方法然后再使用save方法时 ,不会创建TwitterMembership。 Stackoverflow中的许多帖子都说create = new&save,但似乎它们并不相同。

例如:

Project.first.twitter_accounts.create(name: "bar")

正在创建TwitterAccount和TwitterMembership:

SQL (0.5ms)  INSERT INTO "twitter_accounts" ("created_at", "name", "updated_at") VALUES (?, ?, ?)  [["created_at", Thu, 20 Nov 2014 22:01:06 UTC +00:00], ["name", "test_record"], ["updated_at", Thu, 20 Nov 2014 22:01:06 UTC +00:00]]

SQL (0.3ms)  INSERT INTO "twitter_memberships" ("created_at", "project_id", "twitter_account_id", "updated_at") VALUES (?, ?, ?, ?)  [["created_at", Thu, 20 Nov 2014 22:01:06 UTC +00:00], ["project_id", 1], ["twitter_account_id", 8], ["updated_at", Thu, 20 Nov 2014 22:01:06 UTC +00:00]]

但是,当我使用new&createcontrollers / twitter_accounts_controller中执行相同的操作时,它不是在创建TwitterMembership:

def new
  @twitter_account = @project.twitter_accounts.new
end

def create
  @twitter_account = @project.twitter_accounts.new(twitter_account_params)
  @twitter_account.save
end

您能解释一下新保存和创建之间的区别吗? 这样直接在控制器中使用create方法可以吗?

def create
  @twitter_account = @project.twitter_accounts.create(twitter_account_params)
end

提前致谢。

编辑。 这是完整的控制器=>

class TwitterAccountsController < ApplicationController
  before_action :set_project
  before_action :set_twitter_account, only: [:show, :edit, :update, :destroy]

  def new
    @twitter_account = @project.twitter_accounts.new
  end

  def create
    @twitter_account = @project.twitter_accounts.new(twitter_account_params)
    @twitter_account.save
  end

  private
    def set_project
      @project = Project.friendly.find(params[:project_id])
    end

    def set_twitter_account
      @twitter_account = TwitterAccount.friendly.find(params[:id])
    end

    def twitter_account_params
      params.require(:twitter_account).permit(:name, :account_id)
    end
end

修复

您需要在模型上设置逆向关系,以确保buildnew的关联将一致地建立关系,外键和中间关联:

class Project < ActiveRecord::Base
  has_many :twitter_memberships, inverse_of: :project

  has_many :twitter_accounts, through: :twitter_memberships
end

class TwitterMembership < ActiveRecord::Base
  belongs_to :project,         inverse_of: :twitter_memberships
  belongs_to :twitter_account, inverse_of: :twitter_memberships
end

class TwitterAccount < ActiveRecord::Base
  has_many :twitter_memberships, inverse_of: :twitter_account

  has_many :projects, through: :twitter_memberships
end

那应该使这项工作

@twitter_account = Project.first.twitter_accounts.new(name: 'baz')
@twitter_account.save

瞧:

SQL (0.3ms)  INSERT INTO "twitter_accounts" ("created_at", "name", "updated_at") VALUES (?, ?, ?)  [["created_at", "2014-11-21 19:19:06.323072"], ["name", "baz"], ["updated_at", "2014-11-21 19:19:06.323072"]]
SQL (0.1ms)  INSERT INTO "twitter_memberships" ("created_at", "project_id", "twitter_account_id", "updated_at") VALUES (?, ?, ?, ?)  [["created_at", "2014-11-21 19:19:06.324779"], ["project_id", 1], ["twitter_account_id", 7], ["updated_at", "2014-11-21 19:19:06.324779"]]

此外,假设您已经处理了所有发生故障的极端情况,那么使用create是完全可以接受的。 例如:如果失败,您是否向最终用户显示错误? 如果不应该失败,则应引发异常(请参阅create! ),以生成某种通知以通知您失败。

为什么

简而言之,如果没有在has_manyhas_onebelongs_to上的inverse_of设置,Rails不会完全理解将事物粘合在一起的中间模型链。 在某些情况下(例如create ),Rails会做出“最佳猜测”,并可能使事情变得正确。 Rails指南并不清楚,但是有关inverse_of的文档对此进行了说明。

在所有has_manyhas_onebelongs_to关系上设置inverse_of已成为Rails惯用语,应确保不要使用Rails进行猜测。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM