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

时间:2016-07-25 16:42:47

标签: ruby-on-rails ruby-on-rails-4 model-view-controller controllers

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

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

我想从这个社区获得关于我应该遵循设计问题的最佳设计方法的建议/指导。

所以我认为最好的方法是在需要将此信息放在单个族树中时,提出不同的表以便以后使用。因此,当前用户的一个表,一个用于父亲,母亲等的表,每个表具有模型但是使用单个控制器,因为我具有完全相同的html.erb形式,并且每次更改标题以适应兄弟问题。

我已成功创建了流程和操作,例如new,create,show等。但我的问题如下:

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

关于如何使用此代码将创建方法从父级更改为母版,我被困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方法的最佳实践,特别是如果我需要更多具有相同方法的控制器或使用不同方法的相同控制器,或者相同的控制器具有相同的功能(我试过这个并且我得到了“单个函数中更多重定向或渲染”的错误),其次,如果对于这种特殊情况需要遵循的最佳设计,我需要完全相同的字段和操作,但每次都有不同重定向的不同表。

我的路线是:

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
  • 注意:

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

提前谢谢。

2 个答案:

答案 0 :(得分:1)

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

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

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

浏览器获取重定向状态,其下一个应该访问的网址如下:

Location: http://localhost:3000/users/new_mother
然后,浏览器会在该网址上发出新请求,这意味着如果您已准备好路线,则UserController的{​​{1}}操作将会执行。除非您执行某些路由攻击,否则new_mothernew_mother应该是new_father内的操作。重申一下,以防万一,这是一个全新的请求,与第一个返回重定向状态的请求无关。

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

关于设计:

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

render

# simplistic representation create_table "relations" do |t| t.integer "to_person_id" t.integer "is_person_id" t.string "relation_type" end 字段会将亲属类型作为字符串,例如'父亲'。

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

现有的宝石,处理这种架构。其中一些是ancestryacts_as_treeacts-as-dag

答案 1 :(得分:1)

为相同数据设置不同的模型/表不是最佳方法。我认为你应该只需要2个表来处理所有这些(当然是questions的一个表)。 一个表应该是users,其中将存储所有用户。每个用户都会引用它mother及其father 它可以通过自联接/继承来实现。 然后,您需要在此表中为answers提供一个表格,以便存储所有用户的所有答案。所有答案都是motherfathergrand 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

现在在用户控制器中,它非常直接。您只需要一个单独的视图,无论是对于用户还是他的父母或他的祖父,都会针对每种类型的答案进行调用。只需在表单中放入一个隐藏字段,它将告诉您答案的类型,它将存储在答案表中。

因此,如果用户正在回答她的母亲,那么它的价值将是“母亲”。等等。

然后您可以使用&#39;过滤所有用户答案

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