使用相同操作从相同控制器创建表的最佳设计实践是什么

What is the best design practise to create tables from same controller using same actions

我有一个涉及家谱的项目。它首先问你问题(当前用户),然后是关于你父亲的相同问题,然后是关于你母亲的完全相同的问题,一直持续到双方的祖父母。

不幸的是,我尝试了 3 种不同的方法和实现,每次都纠正过去的错误,因为我对 rails 还很陌生。

我想从这个社区获得关于我在遇到设计问题时应该遵循的最佳设计方法的 recommendation/guidance。

所以我认为最好的方法是想出不同的 tables 以便以后当我需要将此信息放入单个家谱时受益。因此,一个 table 给当前用户,一个给父亲、母亲等,每个 table 都有一个模型,但使用一个控制器,因为我有完全相同的 html.erb 形式,每个时间改变 headers 以适应兄弟问题。

我已成功创建流程和操作,例如新建、创建、显示等,但我的问题如下:

我的问题是连续的,最后是家谱。因此,当用户单击继续时,数据将保存在我的数据库的等效 table 中,并且流程将继续下一个 table。

我在如何使具有此代码的创建方法从父亲更改为母亲的问题上停留了 8 个多小时:

  def create
    @user = User.new(user_params)
    if @user.save
      redirect_to :controller => 'users', :action => 'new_father'
    else
      render 'new'
    end
  end

  def user_params
    params.require(:user).permit(:name, :surname, :dob, :location)
  end

其中 users 是 Users_Controller 的名称,'new_father' 是同一控制器中的视图 (new_father.html.erb)。存在其他视图,例如 current_user、new_mother 等

因此,第一次重定向成功实现,因为数据存储在数据库中(第一次重定向 = 从当前用户转到他的父亲),但是我无法在同一个控制器中从父亲转到母亲并且表单保持堆叠在具有以下代码的 new_father.html.erb 视图中:

def create
        @user = User.new(user_params)
        if @user.save
          redirect_to :controller => 'users', :action => 'new_mother'
        else
          render 'new'
        end
      end

  def user_params
    params.require(:user).permit(:name, :surname, :dob, :location)
  end

但是我需要更多的控制器来执行此操作或在名为 create_mother 的同一控制器中执行不同的操作。但是我尝试了所有方法都没有成功。

有人可以(首先)帮助我了解 redirect_to 方法的最佳实践,特别是如果我需要更多具有相同方法的控制器或具有不同方法的相同控制器,或具有相同功能的相同控制器(我试过这和我收到 "more redirections or renderings in a single function") 的错误,其次,对于我需要完全相同的字段和操作但在不同的 table 中每个具有不同重定向的特定情况,最好的设计是什么时间.

我的路线是:

Rails.application.routes.draw do

  # The first page providing information about the current user (novice genealogist).
  get 'users/new'

  # The rest of the pages asking information to form the tree.
  get 'fathers/new_father'
  get 'mothers/new_mother'

  # TODO
  # get 'users/new_grandfather_m'
  # get 'users/new_grandmother_m'

  # The input windows that the user lands on need to create a new record in the database.
  get  '/signup',              to: 'users#new'
  get  '/new_father',          to: 'fathers#new_father'
  get  '/new_mother',          to: 'mothers#new_mother'

  # TODO
  # get  '/new_grandfather_m',   to: 'users#new'
  # get  '/new_grandfather_m',   to: 'users#new'

  # This page will serve as the tree showing information from the above input.
  get  '/tree'  ,              to: 'users#show'

  # Used to update the database by creating records with the above info.
  post '/signup',              to: 'users#create'
  post '/new_father',          to: 'fathers#create_father'
  post '/new_mother',          to: 'mothers#create_mother'

  # TODO
  # post '/new_grandfather_m',   to: 'users#create'
  # post '/new_grandmother_m',   to: 'users#create'

  # The database of our system.
  resources :users

  # The homepage.
  root 'users#new'

end

其他动作是:(基本上我为每个关系都做了新的控制器)

class FatherController < ApplicationController

  # Creates a new instance of the user object (not a record).

  def new_father
    @father = User.new
  end


  # Creates a new record in the database by filling the fields of the new object instance
  # with data.

  def create_father
    @father = User.new(father_params)
    if @father.save
      #redirect_to @user
      redirect_to :controller => 'mothers', :action => 'new_mother'
    else
      render 'new_father'
    end
  end


  # A private method to pass the parameters in the new object instance.

  private

  def father_params
    params.require(:user).permit(:name, :surname, :dob, :location)
  end


  # Extracts information from the database.

  def show_father
    @father = User.find(params[:id])
  end

end

我不需要建立关系等,重要的是想出一个非常简单的树来显示用户的数据并学习 rails 因此关系是一对一的,一对一的许多,许多对许多并不重要。

提前致谢。

您有两个 create 操作,根据您的描述,它们驻留在不同的控制器中。两者都尝试重定向到 UserController,尽管这与之前的不一致。您应该将控制器和路由代码添加到您的问题中以消除歧义。

new_fathernew_mother 不是控制器的视图,而是操作。当你在动作结束时做这样的事情时:

redirect_to :controller => 'users', :action => 'new_mother'

浏览器获得一个重定向状态 url 它接下来应该访问,像这样:

Location: http://localhost:3000/users/new_mother

然后浏览器在 url 处发出新请求,这意味着如果您的路由就位,您的 UserControllernew_mother 操作将被执行。你的 new_mothernew_father 应该是你的 UserController 中的动作,除非你做了一些路由黑客。重申一下,以防万一,这是一个全新的请求,与第一个返回重定向状态的请求无关。

当您调用 redirect_torender 时,Rails 尚未向浏览器发送响应,而是用一些数据标记其内部响应结构并继续其余的操作代码。只有当完整的动作代码被执行时,响应才会被发回。根据其设计,如果您在操作中多次调用这些方法,Rails 会抱怨,因为它会将此视为操作代码中的潜在错误。


关于设计:

您的域中有一些人和关系。人具有相同的属性,无论是用户、父亲或母亲或任何其他亲属。您的域并没有规定人员需要分布在不同的 table 中。其实你主要追求的是家庭成员之间的关系类型。母亲、父亲、姐姐、侄子等是一对人之间的关系。然后将这些关系作为模型呈现是有意义的:

# simplistic representation
create_table "relations" do |t|
  t.integer  "to_person_id"
  t.integer  "is_person_id"
  t.string  "relation_type"
end

relation_type 字段将以字符串形式携带亲属关系类型,例如'father'.

虽然这是构建全面家谱树应用程序的一种正确方法,但它也更复杂。它将涉及单个 table 具有多个关联和递归 SQL 查询,这两个都是相当高级的主题。

现有的 gem 可以处理这种模式。其中一些是 ancestry, acts_as_tree, acts-as-dag.

对相同的数据使用不同的 models/tables 并不是最佳方法。我认为你应该只需要 2 tables 来处理所有这些(当然 questions 需要一个 table)。 一个 table 应该是 users,其中将存储所有用户。每个用户都会引用它的 motherfather 可以自己实现join/inheritance。 然后你需要一个 table for answers 在这个 table 中所有用户的所有答案都将被存储。无论是 motherfather 还是 grand parents 的所有答案。 您只需要一个额外的列来区分答案的类型,无论是 mother/himself/father 还是 grand parents.

每个 answer 将属于给出该答案的 user 并且将属于 question

所以基本上这是这个 schmea 的原始实现。

class User < ActiveRecord::Base
has_many :answers
belongs_to :mother , class_name: 'User' , foreign_key: 'mother_id' #This is telling the user belongs to a mother and it's stored in same table. And mother reference will be stored in mother_id column. So user table should have a column mother_id

belongs_to: father , class_name: 'User', foreign_key: 'father_id' #This is telling the user belongs to a father and it's stored in same table. And father reference will be stored in father_id column. So user table should have a column father_id

has_many :children ,->(user){ where("users.father_id ? or users.mother_id = ?",user.id)} #Every user can have many children. Whether it's a mother or a father 

def grand_father_from_father_side
    father && father.father 
end

def grand_father_from_mother_side
    mother && mother.father
end

#Similary you can get grammy like mother.mother
end


class Question < ActiceRecord::Base
has_many :answers
end

class Answer < ActiveRecord::Base
belongs_to :question
belongs_to :user

#There will be a question_for column in answer table which will tell you this answer was posted for which relation i-e Mother , Father or User Himself

end

现在在用户控制器中,它非常简单。您只需要一个视图,无论是针对用户还是他的 parents 还是他的祖父,每种类型的答案都会被调用。只需在表单中放置一个隐藏字段,它会告诉您答案的类型,并将存储在答案 table 中。

因此,如果用户正在为她的母亲回答,则它的值将为 'Mother' 等等。

然后你可以用'

过滤所有用户回答

user.answers.where(answer_type: 'Mother') 这将 return 一个用户为他母亲回答的所有答案。