Рассмотрим приложение, состоящее из разных типов пользователей, каждый из которых имеет разные профили. Во время регистрации пользователь может выбрать свой тип пользователя (например, покупатель или продавец).
class User < ActiveRecord::Base
belongs_to :profileable, :polymorphic => true
PROFILE_TYPES = %w[Buyer Seller]
end
class Buyer < ActiveRecord::Base
# this is like a buyer profile
has_one :user, :as => :profileable
end
class Seller < ActiveRecord::Base
# this is like a seller profile
has_one :artist, :as => :profileable
end
Массив PROFILE_TYPES
используется в options_for_select
в новом действии контроллера Users, позволяя пользователю выбрать его / ее тип пользователя.
просмотров / пользователей / new.html.erb
<%= form_for @user do |f| %>
<%= label_tag "Type" %>
<%= f.select :profileable_type, options_for_select(User::PROFILE_TYPES) %>
<%# ... %>
<% end %>
Это правильно сохраняет атрибут profileable_type
для пользователя.
Мой вопрос: как только пользователь создан, я бы хотел, чтобы его перенаправили на действие Users # show, где строится правильная профилируемая ассоциация. Форма будет отображаться динамически в зависимости от profileable_type.
Пока что я могу сделать правильную форму со следующим
просмотров / пользователей / show.html.erb
<%= render "#{@user.profileable_type.downcase}/form" %>
Однако это кажется очень неортодоксальным, и я не совсем уверен, как построить ассоциацию. Могу ли я создать ассоциацию при первоначальном создании пользователя? Или я должен создать ассоциацию в Buyers # create и Sellers # create (где указана вышеупомянутая форма)? Должен ли я моделировать данные по-другому?
UPDATE
У меня правильно работает эта функция, добавив attr_accessor :user_type
к модели User.
app / models / user.rb (обновлено)
class User < ActiveRecord::Base
# ...
attr_accessor :user_type
def user_type=(type)
self.profileable = type.constantize.new
self.profileable.save
end
end
views / users / new.html.erb (обновлено)
<%= form_for @user do |f| %>
<%= f.label :user_type %>
<%= f.select :user_type, options_for_select(User::PROFILE_TYPES) %>
<%# ... %>
<% end %>
Это создает правильный связанный объект и сохраняет profileable_type и profileable_id для пользователя. Тем не менее, это все еще кажется неловким и хакерским. Единственный способ обойти это, чтобы иметь отдельные формы для каждого типа пользователя? Это не очень СУХО, так как я не заставляю пользователя заполнять определенные атрибуты для профиля, который он / она выбирает, до тех пор, пока сам пользователь не будет создан.