从父 class 创建一个与 sti 有关系的子 class

Create a subclass from parent class with relationships with an sti

我希望能够通过选择正确的角色在同一表单上创建一个继承自用户的教授,并根据该角色能够 link 并创建教授关系。 所以我做了:

User.rb

class User < ActiveRecord::Base

  attr_accessible :institution_id, :email, :password, :password_confirmation, :remember_me, :civility_id, :first_name,
                  :last_name, :login, :title, :avatar, :role_ids, :users_institutions_levels_attributes,
                  :users_institutions_topics_attributes, :encrypted_pass,
                  :professors_attributes
  belongs_to :institution
  has_many :students
  has_many :professors
  has_many :institutions_levels, through: :students
  accepts_nested_attributes_for :students, :professors
  # Roles
  has_many :roles, :through => :roles_users
  has_many :roles_users
  accepts_nested_attributes_for :roles_users, allow_destroy: true    
  has_many :levels, through: :institutions_levels

  # Validations
  #----------------------------------------
  validates :institution_id, :civility_id, :first_name, :last_name, :email, presence: true, if: 'self.class == User'
  validates_uniqueness_of :email
  validates :email, email: true
  validates :login, presence: true, format: {with: /^([a-zA-Z0-9_\.-]+)*$/}, if: 'self.class == User'
  validates_uniqueness_of :login, scope: [:institution_id]
end

Professor.rb

class Professor < User

  alias_attribute :user_id, :id

  #----- Attributes
  attr_accessible :civility_name, :level_key_names, :topic_key_names, :professor_id, :filtered_topics_attributes
  #----- Filters
  after_save :after_save_actions
  has_many :teacher_exercises
  has_and_belongs_to_many :filtered_topics
  has_many :filtered_levels, through: :filtered_topics
  accepts_nested_attributes_for :filtered_topics, allow_destroy: true
end

_form.html.erb

<%= simple_form_for(@user,  html: {class: 'form-horizontal'}) do |form| %>
  <div class="panel-body">
    <% for field in [:first_name, :last_name, :title, :email, :login, :password] -%>
      <%= form.input field %>
    <% end -%>
  </div>
  <div class="panel-heading clearfix">
    <h3 class="panel-title">
      <%= glyphicon(:user) %>
      <%= t('activerecord.models.role') %>
    </h3>
  </div>
  <%= form.association :roles,
                       collection: Role.accessible_by(Ability.new(current_user)),
                       as: :check_boxes,
                       label: t('commons.role') %>

    <%= form.simple_fields_for(:professors) do |ass| %>
      <div class="panel-heading clearfix">
        <div class="btn-toolbar pull-right">
          <%= link_to_add_association(glyph(:plus), ass, :filtered_topics) %>
        </div>
        <h3 class="panel-title">
          <%= glyphicon(:bookmark) %>
          <%= t('activerecord.models.topics') %>
        </h3>
      </div>
      <div class="fields_filtered_topics">
        <%= ass.simple_fields_for(:filtered_topics) do |form_r| %>
          <%= render(:partial => 'admin/users/form/filtered_topic', :locals => {f: form_r}) %>
        <% end %>
      </div>
    <% end %>
<% end %>

_filtered_topic.html.erb

<li class="fields list-group-item">
  <%= link_to_remove_association(glyphicon(:remove), f) %>
  <%= f.input :topic_id,
              prompt: @current_model.human_attribute_name(:topic.to_s),
              collection: FilteredTopic.accessible_by(Ability.new(current_user)),
              label_method: :topic,
              value_method: :topic_id %>
  <%= f.association :institutions_levels %>
</li>

它带来了很多问题,首先,因为 professor_attributes 只用于关系,它不接受用户参数(登录名、电子邮件等)并且它抱怨它们丢失所以我添加了一个条件如果 class 是 User 则只检查验证,但这是一个更丑陋的变化,因为它们无论如何都不会被保存。我考虑过在控制器中弄乱哈希,但这似乎又是一个非常糟糕的做法。

我找不到关于如何实现我想要的东西的解释,非常感谢您的帮助。

如果是 STI,控制器不能直接创建嵌套实例。

我为解决这个问题所做的是传入一个类型并在控制器上手动创建。例如在你的控制器中

if params[:main_type][:nested_type_attributes] && params[:main_type][:nested_type_attributes][:type]
  nested_type_attributes = params[:main_type].delete(:nested_type_attributes)
  klass = nested_type_attributes.delete(:type).constantize
  params[:main_type][:nested_type] = klass.new(nested_type_attributes)
end