【问题标题】:CRUD method for a model that belongs_to many models Rails属于多个模型的模型的 CRUD 方法 Rails
【发布时间】:2017-10-20 17:13:54
【问题描述】:

我是 Rails 新手,我可能在这里遗漏了一些非常基本的东西:

用户可以为公司的分支机构和部门创建联系人

Branch.rb

class Branch < ApplicationRecord
    belongs_to :company
    has_many :contacts
end

Division.rb

class Division < ApplicationRecord
    belongs_to :company
    has_many :contacts
end

Contact.rb

class Contact < ApplicationRecord
    belongs_to :branch
    belongs_to :division
end

现在用户可以从没有 Division_id 的分支页面创建联系人,并且可以从部门页面创建联系人。

我已经这样定义了我的 routes.rb:

Routes.rb

resources :companies, :shallow => true do
    get 'company_page'
    resources :branches, :shallow => true do
        get 'branch_page'
        resources :contacts
    end 
    resources :divisions, :shallow => true do
        get 'division_page'
        resources :contacts
    end 
end 

因此,如果我从 Branch 或 Division 创建一个联系人,它会转到 contacts#create 方法。

在我的 contacts_controller.rb 中,我有:

def create
    @newContact = Contact.new(contact_params)
    id = @division = @branch = nil
    isBranch = false
    if params[:branch_id] != nil
        isBranch = true
        id = params[:branch_id]
    else
        isBranch = false
        id = params[:division_id]
    end 
    if isBranch
      branch = Branch.find(id) 
      @newContact.branch = branch
      @branch = branch
    else
      division = Division.find(id) 
      @newContact.division = division
      @division = division
    end  

    respond_to do |format|
        if @newContact.save
          format.js
          format.html { render :nothing => true, :notice => 'Contact created successfully!' }
          format.json { render json: @newContact, status: :created, location: @newContact }
        else
          format.html { render action: "new" }
          format.json { render json: @newContact, status: :unprocessable_entity }
        end
    end     
end

但我在@newContact.save期间面对ActiveRecord Error

我确信我在这里做了一些根本上非常错误的事情,Rails 以另一种我不知道的优雅方式处理这些事情。

【问题讨论】:

  • 错误是什么?
  • Completed 500 Internal Server Error in 265ms (ActiveRecord: 66.8ms)
  • 我猜这个错误是因为Contact 有两个属于关联,但你只给它一个。 log/development.log 中的错误是什么?
  • 是的,你是对的。我想知道如何处理。问题是@newContact.save is false,因此它会转到respond_to do |format| block 的else 块。
  • 你可以做belongs_to :branch, optional: true; belongs_to :division, optional: true

标签: ruby-on-rails ruby activerecord associations model-associations


【解决方案1】:

正如@Anthony 所说,您需要将belongs_to 关联设为可选:

# app/models/contact.rb

class Contact < ApplicationRecord
  belongs_to :branch, optional: true
  belongs_to :division, optional: true
end

但另一个问题是params[:division_id]params[:branch_id] 总是为零。这两个键都存在于[:contact] 键中。所以你得到的错误应该是ActiveRecord::RecordNotFound: Couldn't find Division with 'id'=

所有这些条件逻辑都是不必要的。您可以与给出的任何参数建立新的联系。此外,您应该使用 Ruby 约定来命名变量,即 snake_case 而不是 camelCase。

最后,我假设您希望将 HTML 请求重定向到分支或部门显示页面,具体取决于关联的页面。所以我添加了逻辑来做到这一点。

这是控制器#create操作的快速重构:

  def create
    @new_contact = Contact.new(contact_params)

    if @new_contact.save
      branch = @new_contact.branch
      division = @new_contact.division
      redirect_path = branch ? branch_path(branch) : division_path(division)

      respond_to do |format|
        format.js
        format.html { redirect_to redirect_path, :notice => 'Contact created successfully!' }
        format.json { render json: @new_contact, status: :created, location: @new_contact }
      end
    else
      respond_to do |format|
        format.html { render action: "new" }
        format.json { render json: @new_contact, status: :unprocessable_entity }
      end
    end
  end

这证明它有效:

# spec/controllers/contacts_controller_spec.rb

require 'rails_helper'

RSpec.describe ContactsController, type: :controller do
  let(:company) { Company.create!(name: 'Company Name') }
  let(:division) { Division.create!(name: 'Division Name', company: company) }
  let(:branch) { Branch.create!(name: 'Branch Name', company: company) }

  describe '#create' do
    context 'when created with a division id' do
      let(:attributes) { {'division_id' => division.id, 'name' => 'Contact Name'} }

      it 'creates a contact record and associates it with the division' do
        expect(Contact.count).to eq(0)
        post :create, params: {contact: attributes}

        expect(Contact.count).to eq(1)
        contact = Contact.first
        expect(contact.division).to eq(division)
      end
    end

    context 'when created with a branch id' do
      let(:attributes) { {'branch_id' => branch.id, 'name' => 'Contact Name'} }

      it 'creates a contact record and associates it with the branch' do
        expect(Contact.count).to eq(0)
        post :create, params: {contact: attributes}

        expect(Contact.count).to eq(1)
        contact = Contact.first
        expect(contact.branch).to eq(branch)
      end
    end
  end
end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多