簡體   English   中英

Rails將記錄復制到另一個表

[英]Rails copy a record to another table

我有一張叫工作jobplans的表,一個叫工作workorders的表。 他們有許多相似的字段(列)。

我想有一個按鈕,就會調用代碼創建一個新的workorder ,並從復制類似領域jobplan

我在另一個問題中找到了這樣的代碼:

@jobplan = Jobplan.find(params[:id]) # find original object
@workorder = Workorder.create(@jobplan.attributes)

但是-

該代碼可以工作嗎? 如果是,它將去哪里? 它可以在帶有按鈕的視圖頁面上顯示嗎? 控制器? 模型?

謝謝你的幫助!

我將創建一個控制器動作,例如copy_to_workorder然后將此按鈕綁定到該控制器動作。 我認為將此動作JobplanControllerJobplanController上是JobplanController

因此,從高層次看:

  1. 您的視圖將具有一個向jobplan/:id/copy_to_workorder提交請求的表單(可能是POST )。 您還將創建此路線。

  2. 您的JobplanController將具有一個copy_to_workorder操作,該操作基本上可以在上面完成您的代碼,盡管對此進行一些附加驗證是一個好主意。

  3. 然后copy_to_workorder操作將執行某些操作...也許重定向到JobplanController#index操作?

Jobplan上創建實例方法也可能更干凈一些,比如Jobplan create_workorder! 這將執行上面的兩行代碼。

乍一看,我覺得您發布的代碼可以正常工作。 它屬於哪里是一個更有趣的問題。

我的第一個想法是考慮這些模型類是否可以很好地對您的應用程序要服務的問題域進行建模。 具有幾乎相同的字段集的多個模型似乎是一個警告信號,這些共同的屬性應該存在於一個模型上,並且工作流的不同階段應該由不同的類表示。

在這里猜測域名。 有一些計划具有一個JobStatus來跟蹤工作流程狀態的那些變化是否更合適? Jobplan和Workorder都可以有一個藍圖(或任何捕獲這些共享屬性的東西)嗎?


無論如何,讓我們假設這些模型非常適合您討論和使用該領域核心概念的方式。 那么該行為應該在哪里存在,我們如何調用它?

無論我們如何實現,我們都可以從描述我們希望用戶看到的行為開始。 例如,如果應用程序使用Capybara功能規格,我們可能會編寫如下內容:

feature 'the job plan show page' do
  given(:user) { FactoryGirl.create :job_supervisor }
  given(:jobplan) { FactoryGirl.create :jobplan }

  background do
    login user
  end

  # ...

  scenario 'creating a work order from the job plan' do
    visit jobplan_path(jobplan)
    click_link 'Create work order'
    expect(page).to have_content 'Work order created'
    expect(current_path).to match /\/workorders\/\d/
    # ...
  end
end

該測試尚未通過,但我們會到達那里。

我發現嘗試將Rails控制器限制為基本的CRUD(創建,讀取,更新,刪除)操作很有幫助。 如果應用僅公開API,則這些映射將映射到createindexshowupdatedestroy動作。 當應用程序直接提供HTML頁面時,我們還可以添加editnew動作,以提供用於createupdate端點的界面。 每當我們擴展到這7個動作之外時,就警告我們可能沒有很好地對問題進行建模,並且我們的控制器承擔了太多的責任。

在這種情況下,我們知道我們要創建一個新的Workorder 創建Workorder已有一個定義明確的主目錄; WorkordersControllercreate動作,因此讓我們嘗試在WorkordersController實現此行為。

要創建工作Workorder我們需要一堆屬性。 我們可以讓客戶端將它們包含在此create操作的POST請求中,但這將它們置於客戶端的控制之下。 如果不希望客戶從相應的Jobplan上更改它們的值,那么這似乎是個壞主意。 相反,似乎最好只接收Jobplanid ,如問題中已經顯示的那樣。

我們可能只是將Jobplan id作為POST參數傳遞,但我認為有一個更優雅的解決方案。 通過聲明Workorder的下一個嵌套的資源Jobplan我們可以表達我們的網址,這些模型之間的關系。 這會導致一些非常自然的響應,例如,如果您嘗試使用不存在的Jobplan ID創建工作Workorder ,則404響應Workorder意義。

我們當然也可以在測試中描述我們希望控制器提供的特定行為:

describe WorkorderController do
  let(:jobplan) { FactoryGirl.create :jobplan }

  describe '#create' do
    context 'given a valid jobplan id' do
      it 'creates a new workorder' do
        expect { post jobplan_id: jobplan.id }.to change {Workorder.count}.by(1)
      end

      it 'redirects to the new workorder' do
        post jobplan_id: jobplan.id
        expect(response).to be_redirect
      end

      it 'copies the jobplan attributes to the new workorder' do
        post jobplan_id: jobplan.id
        expect(assigns(:workorder).location).to eq jobplan.location
        # ...
      end
    end
  end
end

這將失敗,因為我們嘗試到達的路線是不確定的,因此我們可以從此處開始。

resources :jobplans do
  resources :workorders, only: [:create]
end
resources :workorders, only: [:show]

將使我們能夠發布到/jobplans/<jobplan_id>/workorders以創建新的工作訂單。 請注意,這里我們聲明了路線,這樣適合在工作計划下創建工作單,但是所有其他允許的操作仍然使用頂層工作單路線。 將來,我們可能會回來擴展這些選項。 也許我們將希望能夠獲取/jobplans/<jobplan_id>/workorders以獲得特定工作計划下所有工作單的列表,而/workorders返回系統中的每個工作單。

現在我們可以執行控制器動作。

def create
  jobplan = Jobplan.find(params[:jobplan_id])
  @workorder = Workorder.create(@jobplan.attributes)
  redirect_to workorder_path(@workorder)
end

最終的想法是,我們可能不想丟失使用哪個Jobplan來創建給定的Workorder因此我們可以將該關系添加到模型中並清理一些東西。 從工作計划創建工作單變得越來越復雜,因此我們可能要求控制器做太多事情。 如果可能會有副作用,例如需要發送變更通知或更新賬單,我們可能會將創建工作訂單的責任轉移到模型或服務對象中。 最終,我們的控制器動作可能類似於:

def create
  jobplan = Jobplan.find(params[:jobplan_id])
  @workorder = Workorder.create_from_jobplan(jobplan)
  redirect_to workorder_path(@workorder)
end

希望這看起來是一條合理的道路和最終解決之道。 我對您的應用程序需要什么以及您可能使用的工具做了很多假設,並且並未實際運行上面的任何代碼,並且忽略了我通常可能編寫的許多其他測試,但是我相信您可以決定是否適當地應用它。 我不想再通過測試測試來回答這個問題,但是如果上面的內容不熟悉,我會喜歡Jared 在測試Rails開發中外部的描述。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM