Rails Relationship(has_many/belongs_to)已完成

Jak*_*ake 2 ruby-on-rails

所以,自从我和人际关系玩起来已经有很长一段时间了,我想确保我做得对.

在我的客户模型中,我有:

class Client < ApplicationRecord
   has_many :projects, dependent: :destroy
end
Run Code Online (Sandbox Code Playgroud)

在我的项目模型中,我有:

class Project < ApplicationRecord
   belongs_to :client
end
Run Code Online (Sandbox Code Playgroud)

所以我知道那是设定的.然后抓住我放在项目控制器中的项目:

def create
 @client = Client.find(params[:client_id])
 @project = @client.project.new(project_params)
 flash[:notice] = "Project created successfully" if @client.project << @project
 respond with @project, location: admin_project_path
end
Run Code Online (Sandbox Code Playgroud)

我是否需要在我的节目中放一些同样的东西?

关系中我还缺少什么?

jvi*_*ian 5

我会这样想:

def create
  @client = Client.find(params[:client_id])
  @project = @client.project.new(project_params)
  flash[:notice] = "Project created successfully" if @client.project << @project
  respond with @project, location: admin_project_path
end
Run Code Online (Sandbox Code Playgroud)

看起来更像是:

def create
  @client = Client.find(params[:client_id])
  @project = @client.projects.new(project_params)
  if @project.save
    # do success stuff 
  else
    # do failure stuff
  end
end
Run Code Online (Sandbox Code Playgroud)

注意

@project = @client.project.new(project_params)
Run Code Online (Sandbox Code Playgroud)

应该:

@project = @client.projects.new(project_params)
Run Code Online (Sandbox Code Playgroud)

正如Yechiel K所说,没有必要这样做:

@client.project << @project
Run Code Online (Sandbox Code Playgroud)

以来:

@project = @client.projects.new(project_params)
Run Code Online (Sandbox Code Playgroud)

将自动设置client_id为新的@project.顺便说一句,如果你想将添加projectclient手动,然后它的:

@client.projects << @project
Run Code Online (Sandbox Code Playgroud)

(注意projectsproject.)

如果没有clientwith params[:client_id],@client = Client.find(params[:client_id])则会抛出错误.你可能应该包括一个救援区.或者,我更喜欢:

def create
  if @client = Client.find_by(id: params[:client_id])
    @project = @client.projects.new(project_params)
    if @project.save
      # do success stuff 
    else
      # do failure stuff
    end
  else
    # do something when client not found
  end
end
Run Code Online (Sandbox Code Playgroud)

而且,respond with不是一件事.respond_with是一件事.(我相信它已被转移到一个单独的宝石,responders.)从你的代码中不清楚你是否需要不同的回答,比如说,htmljs.如果没有,那么我认为它更像是:

def create
  if @client = Client.find_by(id: params[:client_id])
    @project = @client.projects.new(project_params)
    if @project.save
      flash[:notice] = "Project created successfully"
      redirect_to [@client, @project]
    else
      # do failure stuff
    end
  else
    # do something when client not found
  end
end
Run Code Online (Sandbox Code Playgroud)

这假设你的路线看起来像:

Rails.application.routes.draw do

  resources :clients do 
    resources :projects
  end

end
Run Code Online (Sandbox Code Playgroud)

在这种情况下,rails将解析[@client, @project]为正确的路由/路径.

作为DaveMongoose提到,你可以移动@client = Client.find_by(id: params[:client_id])到一个before_action.这很常见.这里有一个关于为什么不这样做的讨论.就个人而言,我曾经这样使用before_action,但不再这样了.作为替代方案,您可以:

class ProjectsController < ApplicationController 

  ...

  def create 
    if client 
      @project = client.projects.new(project_params)
      if @project.save
        flash[:notice] = "Project created successfully"
        redirect_to [client, @project]
      else
        # do failure stuff
      end
    else
      # do something when client not found
    end
  end

private

  def client 
    @client ||= Client.find_by(id: params[:client_id])
  end

end
Run Code Online (Sandbox Code Playgroud)

更进一步,你可以这样做:

class ProjectsController < ApplicationController 

  ...

  def create 
    if client 
      if new_project.save
        flash[:notice] = "Project created successfully"
        redirect_to [client, new_project]
      else
        # do failure stuff
      end
    else
      # do something when client not found
    end
  end

private

  def client 
    @client ||= Client.find_by(id: params[:client_id])
  end

  def new_project 
    @new_project ||= client.projects.new(project_params)
  end

end
Run Code Online (Sandbox Code Playgroud)