Rails - 如何从单一 Table 继承创建正确类型的对象?

Rails - How to create the right kind of object from Single Table Inheritance?

我已经建立了一个 Rails 项目来使用单一 Table 继承,因为我有两种类型的 Users - Senders 和 Receivers。 Senderpublic_key 属性,Receiverphone_number 属性。他们通过 User.

共享 nameemailpassword 属性

我的问题是,在 User 控制器的 create 函数中,我正在尝试创建一种或另一种类型 - SenderReceiver - 基于我的注册表单上单选按钮的值。

设置如下:

用户模型

class User < ActiveRecord::Base

  validates :name,  :presence => true, :length => { maximum: 50 }
  validates :password, presence: true

  self.inheritance_column = :user_type

  # We will need a way to know which types with subclass the User model
  def self.user_types
    %w(Sender Receiver)
  end
end

class Sender < User; end
class Receiver < User; end

发件人模型

class Sender < User
  validates :public_key,  :presence => true
end

接收器型号

class Receiver < User
  validates :phone_number,  :presence => true, :length => 10
end

用户控制器

class UsersController < ApplicationController
  #  before_action :set_user, only: [:show, :edit, :update, :destroy]
  before_action :set_user_type

  def index
    @users = user_type_class.all
  end

  def show
    @user = User.find(params[:id])
  end

  def new
    @user = User.new
  end

  def create
    if(user_type.eql? "receiver")
      @user = Receiver.new(user_params)
    else
      @user = Sender.new(user_params)
  end
  ...
  private

    # allow views to access user_type
    def set_user_type
      @user_type = user_type
    end

    def user_type
      User.user_types.include?(params[:type]) ? params[:type] : "User"
    end

    def user_type_class
      user_type.constantize
    end

    # Use callbacks to share common setup or constraints between actions.
    def set_user
      @user = User.find(params[:id])
    end

    def user_params
      params.require(:user).permit(:name, :email, :password, :confirmation_password, :user_type)
    end
end

新用户表单

<%= form_for(@user) do |f| %>
...
  <div class="user-type">
    <%= f.label :user_type, class: 'form-control' %>
    <%= radio_button_tag(:user_type, "sender")  %>
    <%= label_tag(:user_type_sender, "I am a Sender")  %>
    <%= radio_button_tag(:user_type, "receiver")  %>
    <%= label_tag(:user_type_receiver, "I am a Receiver")  %>
  </div>
  <div class="field">
    <%= f.label :name %><br>
    <%= f.text_field :name %>
  </div>
 ...
<% end %>

User 控制器的 create 方法中,我尝试使用此 if 语句创建正确的 User 类型:

if(user_type.eql? "receiver")
  @user = Receiver.new(user_params)
else
  @user = Sender.new(user_params)

根据此处 User 表格中记录的值:

<%= radio_button_tag(:user_type, "sender")  %>
<%= label_tag(:user_type_sender, "I am a Sender")  %>
<%= radio_button_tag(:user_type, "receiver")  %>
<%= label_tag(:user_type_receiver, "I am a Receiver")  %>

然而,我总是else语句中得到一个Sender类型的对象。我认为这意味着我的 if 语句 if(user_type.eql? "receiver") 有问题;但是,我不知道是什么。

想法?

首先,我认为您不需要 set_user_type 方法,因为您没有使用其设置的 @user_type 变量。也从控制器顶部取出before_action

其次,在 user_type 方法中,您需要将 params[:type] 更改为 params[:user_type],因为这是 HTML.

中单选按钮标签的名称
def user_type
  User.user_types.include?(params[:user_type]) ? params[:user_type] : "User"
end

第三,你还需要将单选按钮标签的值属性大写为"Sender"和"Receiver",因为这就是你在User.user_types数组中的内容。

<%= radio_button_tag(:user_type, "Sender")  %>
<%= radio_button_tag(:user_type, "Receiver")  %>

免责声明:未经测试,但应该可以解决您的问题。