Rails Relationship(has_many / belongs_to)已完成

时间:2018-03-12 17:33:59

标签: ruby-on-rails

因此,我和人际关系玩了很长时间,我想确保我做得对。

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

interleaveColumns = function(v) { 
    c(1, unlist(split(2:length(v), 1:((length(v)-1)/2)), use.names = FALSE)) 
}

df = tibble(val1 = 5:10, val2 = 10:15, val3 = 15:20, val4 = 25:30, val5 = 1:6);

# mutate_at can be given a named list to create a new column 
# for each existing columnt (appended to the end => we need 
# to reorder the columns and interleave the new columns with 
# the old columns using the interleaveColumns function)

df %>%
     mutate_at(vars(-1), list(rel = function(v) v/.[[1]])) %>% 
     select(interleaveColumns(.))

# A tibble: 6 x 9
   val1  val2 val2_rel  val3 val3_rel  val4 val4_rel  val5 val5_rel
  <int> <int>    <dbl> <int>    <dbl> <int>    <dbl> <int>    <dbl>
1     5    10     2.00    15     3.00    25     5.00     1    0.200
2     6    11     1.83    16     2.67    26     4.33     2    0.333
3     7    12     1.71    17     2.43    27     3.86     3    0.429
4     8    13     1.62    18     2.25    28     3.50     4    0.500
5     9    14     1.56    19     2.11    29     3.22     5    0.556
6    10    15     1.50    20     2.00    30     3.00     6    0.600

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

class Client < ApplicationRecord
   has_many :projects, dependent: :destroy
end

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

class Project < ApplicationRecord
   belongs_to :client
end

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

我为关系而遗漏的其他东西?

2 个答案:

答案 0 :(得分: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

看起来更像是:

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

请注意

@project = @client.project.new(project_params)

应该是:

@project = @client.projects.new(project_params)

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

@client.project << @project

自:

@project = @client.projects.new(project_params)

会自动在新client_id上设置@project。顺便说一句,如果你想手动向project添加client,那就是:

@client.projects << @project

(注意projectsproject。)

如果client没有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

此外,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

这假设您的路线类似于:

Rails.application.routes.draw do

  resources :clients do 
    resources :projects
  end

end

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

正如DaveMongoose所提到的,你可以@client = Client.find_by(id: params[:client_id])移动到before_action。这很常见。 Here's讨论为什么不这样做。就个人而言,我过去常常使用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

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

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

答案 1 :(得分:2)

我会替换这一行:

flash[:notice] = "Project created successfully" if @client.project << @project

使用:

flash[:notice] = "Project created successfully" if @project.save

无需手动将@project添加到@client.projects,当您使用@client.projects.new创建时,它会自动添加,您唯一遗漏的是使用.new创建内容并不会将其保留在数据库中,而是通过调用@project.save来完成。

对于您的展示操作,我不确定您是指客户的展示页面还是项目,但在任何一种情况下,您都会使用params[:id]检索它(除非你使用一些嵌套路由。)