У меня проблема с разделением на подклассы моделей Rail.Предположим, у вас есть модель User
и несколько ее подклассов (пользовательских типов), в которых хранятся определенные методы и ассоциации, например: Director
, Admin
, Trainee
, Instructor
и т. Д. Это просто "наследование одной таблицы ".Проблема двоякая.
пути / URL часто приводят к сбоям или странным вещам, когда вы передаете подкласс, а не базовый класс.Вот пример:
<% if user.enabled? %>
<%= link_to 'Disable', disable_user_path(user) %>
<% else %>
<%= link_to 'Enable', enable_user_path(user) %>
<% end %>
Если вы передадите модель 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">}
Очевидно, что это ведет себя неправильно.Как мы можем заставить рельсы использовать базовый класс все время?
Еще более беспокоят формы (я использую simple_form
).Допустим, у вас есть форма /profile
.Вы хотите, чтобы все User
подклассы имели равный доступ к нему, и вы не хотите иметь дело с их подклассами в особых случаях;он должен быть на 100% общим.
По какой-то причине, если пользователь является Admin
, он отправит хэш параметров как
params[:admin]
Еще хуже, если вы просматриваете источникформы, на самом деле он говорит 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 %>
Вот действия контроллера, чтобы сначала визуализировать представление, и когда я отправляю форму:
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
Помимо придумывания некоторых довольно не элегантных решений (особенно проблем с формами), яв недоумении относительно того, как я могу их исправить.Должен быть лучший способ справиться с этими ситуациями.