从父 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
我希望能够通过选择正确的角色在同一表单上创建一个继承自用户的教授,并根据该角色能够 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