Fir*_*lem 1 ruby inheritance model ruby-on-rails subclass
我对子类化铁的模型有问题.假设你有一个User模型,它的几个子类(用户类型)存储特定的方法和协会,例如:Director,Admin,Trainee,Instructor,等这只是简单的"单表继承".问题是2倍.
当您传递子类而不是基类时,路径/ URL经常崩溃或做一些奇怪的事情.这是一个例子:
<% if user.enabled? %>
<%= link_to 'Disable', disable_user_path(user) %>
<% else %>
<%= link_to 'Enable', enable_user_path(user) %>
<% end %>
Run Code Online (Sandbox Code Playgroud)
如果你传入一个User模型,它就可以正常工作.但是如果你传递一个子类Admin,就会抛出这个异常:
No route matches {:controller=>"users", :action=>"disable", :id=>#<Admin id: 1, first_name: "Ken", ..., created_at: "2011-05-23 21:01:35", updated_at: "2011-05-23 21:04:28">}
Run Code Online (Sandbox Code Playgroud)
显然,这表现不正常.我们怎样才能让rails一直使用基类?
形式更令人不安(我正在使用simple_form).假设你有一张/profile表格.您希望所有User子类同等地访问它,并且您不希望在特殊情况下处理它们的子类; 它应该是100%通用的.
出于某种原因,如果用户是a Admin,则会将params hash发布为
params[:admin]
Run Code Online (Sandbox Code Playgroud)
更糟糕的是,如果你查看表单的来源,它实际上是user[first_name]代替admin[first_name],而是一些东西肯定是搞砸了!实例变量也是@user如此,所以我不明白它为什么要发布到params[:admin].
这是(2)的表单视图代码:
<%= simple_form_for(@user, :url => profiles_path, :method => :put, :html => {:multipart => true}) do |f| %>
<%= f.error_notification %>
<div class="form">
<fieldset>
<legend>Personal Information</legend>
<%= f.input :first_name %>
<%= f.input :last_name %>
</fieldset>
<fieldset>
<legend>Credentials</legend>
<%= f.input :email %>
</fieldset>
<fieldset>
<legend>Preferences</legend>
<%= f.input :receive_email_notifications %>
<%= f.input :receive_newsletters %>
<%= f.input :allow_private_messages %>
</fieldset>
<fieldset>
<legend>Avatar</legend>
<p>
Select an image from your computer to use as your avatar. You will be given the oppurtunity
to crop this image further after your image has been uploaded.
</p>
<%= f.input :avatar, :as => :file, :label => "Select File" %>
<%= f.hidden_field :avatar_cache %>
</fieldset>
<div class="actions">
<%= f.button :submit, :value => "Update Profile" %>
<%= link_to 'Cancel', profiles_path %>
</div>
</div>
<% end %>
Run Code Online (Sandbox Code Playgroud)
以下是首次呈现视图的控制器操作以及提交表单时的操作:
def edit
@user = User.find(current_user.id)
end
def update
@user = User.find(current_user.id)
if @user.update_attributes(params[:user]) # <-- this bombs for Admin subclass
if params[:user][:avatar] # <-- this would bomb also.
redirect_to(crop_avatar_profiles_path)
else
redirect_to(profiles_path, :notice => 'Your profile was successfully updated.')
end
else
render :action => "edit"
end
end
def crop_avatar
@user = User.find(current_user.id)
end
def update_avatar
@user = User.find(current_user.id)
@user.crop(params[:x].to_i, params[:y].to_i, params[:h].to_i, params[:w].to_i)
redirect_to(profiles_path, :notice => 'Your profile and avatar was successfully updated.')
end
Run Code Online (Sandbox Code Playgroud)
除了思考一些非常不优雅的解决方案(特别是对于表单问题),我不知道如何解决它们.必须有更好的方法来处理这些情况.
= simple_form_for @fruit, :as => :fruit do |form|
Run Code Online (Sandbox Code Playgroud)
@fruit可以是任何类(橙色,苹果,梨),它仍然会在输入前加上"水果",从而params[:fruit]每次都给出一个.