簡體   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