Комментарии 41
Изменения в attr_accessible нужны, чтобы можно было сохранять данные «пачками», а не по одной.
Без объявления attr_accessible вообще невозможно сохранить данные кроме тех, что Devise определяет по-умолчанию.
А чем Вас не устраивает вариант 2-х отдельных «ролей» в Devise?
Потому, что полиморфизм позволяет ассоциировать одну модель, например Comment, с несколькими моделями сразу через одну единственную полиморфную связь, что обеспечивает простоту и краткость кода, ну и вообще принцип DRY уж очень подкупает выгодами его применения.
Принцип «Polymorphism» я понимаю, но по обстоятельству, может быть целесообразным использовать два типа Юзеров. Я понимаю если это разные уровни «Редактоpа» в какой-то блоговой системе, но если это Админ и Юзер, или, Читатель и Публикатор, то тут сама идея полиморфизма как-то ни к месту.
Спасибо за поправку.
Две роли меня не устроили потому, что 2 роли — это 2 формы регистрации и 2 формы входа (насколько я понял). То есть типа «Войти как пользователь» и «Войти как администратор».
Тут же предполагается, что у них таки есть общие поля, но есть и различные.
+ я не очень понял, если делать 2 разных модели, то у меня будет user_signed_in?, admin_signed_in?, authenticate_user! и authenticate_admin!, что меня не устраивает, потому что контроллеры они пользуются одними и теми же, просто с разными правами.
Две роли меня не устроили потому, что 2 роли — это 2 формы регистрации и 2 формы входа (насколько я понял). То есть типа «Войти как пользователь» и «Войти как администратор».
Тут же предполагается, что у них таки есть общие поля, но есть и различные.
+ я не очень понял, если делать 2 разных модели, то у меня будет user_signed_in?, admin_signed_in?, authenticate_user! и authenticate_admin!, что меня не устраивает, потому что контроллеры они пользуются одними и теми же, просто с разными правами.
Да все просто на самом деле, роли — это не то чем должен заведовать devise. В вашем случае это ответственность cancan — github.com/ryanb/cancan/wiki/Role-Based-Authorization
Мне больше понравился github.com/stffn/declarative_authorization, рекомендую ознакомиться
Мне больше понравился github.com/stffn/declarative_authorization, рекомендую ознакомиться
Да, особенно хорош declarative_authorization при наличии неймспейсов в контроллерах :) Поэтому я больше в d_a ни ногой:)
А по поводу ролей — если бы поля были одинаковые у обоих типов юзеров — нет проблем. Но они, с одной стороны, совсем разные сущности (и надо бы создать 2 разных девайсовы модели), с другой стороны — очень похожие и имеют много общего.
У типов как «обычный пользователь» и «администратор» больше разных аттрибутов чем одинаковых. Поэтому, будет правильным сделать две разные модели для них. Чего вы добились полиморфизмом? 3 таблицы в BD vs 2-х.
Про админа речи не идет вообще, речь о том, что нужны Заказчик и Исполнитель.
Извиняюсь за БД, имелось ввиду DB. Пусть будет «заказчик» и «потребитель», но всё равно, у них разные атрибуты. Всё таки я сторонник де-нормализации БД. Пускай будет больше таблиц, чем больше программного вычисления.
И как в таком случае будут вести себя контроллеры и представления? «Войти как заказчик», «Войти как исполнитель», «Зарегистрироваться как заказчик», «Зарегистрироваться как исполнитель»?
Что тогда делать в контроллерах, везде писать «authenticate_customer!», «authenticate_executive!» в before_filter'ах?
Всегда проверять на customer_signed_in? и executive_signed_in? мне как-то тоже не очень улыбается. Я выбрал лучшее решение для меня (как мне кажется), в некоторых ситуациях да, лучше сделать 2 модели вместо трех, а полиморфизм оставить до лучших времен, но, имхо, это не тот случай.
Что тогда делать в контроллерах, везде писать «authenticate_customer!», «authenticate_executive!» в before_filter'ах?
Всегда проверять на customer_signed_in? и executive_signed_in? мне как-то тоже не очень улыбается. Я выбрал лучшее решение для меня (как мне кажется), в некоторых ситуациях да, лучше сделать 2 модели вместо трех, а полиморфизм оставить до лучших времен, но, имхо, это не тот случай.
ognevsky, а можете вьюхи показать. У меня аналогичная задача, но вот получаю ошибку при сабмите формы «undefined method `primary_key' for String:Class»
Моя вью регистрации:
Моя вью регистрации:
<div class="center">
<h2>Регистрация</h2><br/>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div><%= f.select :character, options_for_select([["Физлицо", "Individual"], ["Компания", "Company"]]) %></div>
<div><%= f.email_field :email, :placeholder => 'Адрес электронной почты' %></div>
<div><%= f.password_field :password, :placeholder => 'Пароль' %></div>
<div><%= f.password_field :password_confirmation, :placeholder => 'Подтверждение пароля' %></div>
<div><%= f.submit "Зарегистрироваться", :class => 'btn btn-danger' %></div>
<% end %>
<%= render "devise/shared/links" %>
</div>
pastie.org/4399931
У меня вот такое, я использовал formtastic, с встроенным форм-билдером не пробовал, если честно.
У меня вот такое, я использовал formtastic, с встроенным форм-билдером не пробовал, если честно.
Ага, разобрался еще до ответа, спасибо.
Андрей, такой еще вопрос: вот выбирает юзер в форме регистрации тип пользователя, как динамически перестроить форму?
Я сделал два partial, в которые поместил обязательные для заполнения поля. По умолчанию у меня выбран 1й тип юзера в селекте и отображается 1й partial. Но когда выбрал в селекте 2й тип юзера, должен отобразиться 2й partial вместо 1го.
Андрей, такой еще вопрос: вот выбирает юзер в форме регистрации тип пользователя, как динамически перестроить форму?
Я сделал два partial, в которые поместил обязательные для заполнения поля. По умолчанию у меня выбран 1й тип юзера в селекте и отображается 1й partial. Но когда выбрал в селекте 2й тип юзера, должен отобразиться 2й partial вместо 1го.
Тут javascript в помощь, я не забый большой его знаток, поэтому и советовать особенно ничего не буду. Лучший вариант — Ajax'ом подгружать вторую форму.
Ок, этот вариант мне сразу в голову пришел, думал просто есть другой вариант. А у Вас в приложении заполнение данных юзера было на втором шаге после ввода общих полей или ajax-ом тоже форму меняли?
Попробовал указать по умолчанию 1й тип юзера. В его модели есть обязательные к заполнению при регистрации поля, которые я влючаю в форму: pastebin.com/aY74NtDe
Но когда рендериться страница с формой полей этих нет, только поля модели User.
В чем может быть причина, я не правильно описываю форму? Или т.к. запись еще не сохранена (т.е.) в базе фактически нет записи user (и заполненных полей character_id, character_type), то мы не можем и заполнить данные модели Individual? (хотя я больше расчитываю на то, что я ошибся где-то).
Но когда рендериться страница с формой полей этих нет, только поля модели User.
В чем может быть причина, я не правильно описываю форму? Или т.к. запись еще не сохранена (т.е.) в базе фактически нет записи user (и заполненных полей character_id, character_type), то мы не можем и заполнить данные модели Individual? (хотя я больше расчитываю на то, что я ошибся где-то).
Полезным будет почитать про вложенные ресурсы, про accepts_nested_attributes_for тоже. Возможно, в этом проблема.
Решил проблему с отображением: gist.github.com/3288189, gist.github.com/3288198
Но при регистрации теперь получаю ошибку «ArgumentError in RegistrationController#create»
Cannot build association character. Are you trying to build a polymorphic one-to-one association?
Request
Parameters:
{«utf8»=>"✓",
«authenticity_token»=>«62bE9GNDQ1QFn5UDP34EmxLlHSRiKzCSPwJO8BiNuYU=»,
«user»=>{«character_type»=>«Company»,
«email»=>"",
«password»=>"[FILTERED]",
«password_confirmation»=>"[FILTERED]",
«character_attributes»=>{«name»=>""}},
«commit»=>«Зарегистрироваться»}
Но при регистрации теперь получаю ошибку «ArgumentError in RegistrationController#create»
Cannot build association character. Are you trying to build a polymorphic one-to-one association?
Request
Parameters:
{«utf8»=>"✓",
«authenticity_token»=>«62bE9GNDQ1QFn5UDP34EmxLlHSRiKzCSPwJO8BiNuYU=»,
«user»=>{«character_type»=>«Company»,
«email»=>"",
«password»=>"[FILTERED]",
«password_confirmation»=>"[FILTERED]",
«character_attributes»=>{«name»=>""}},
«commit»=>«Зарегистрироваться»}
ognevsky, спасибо за хорошую, подробную статью!
Статья конечно интересная, но подробностей как раз таки не хватает. Вы так и не написали зачем вам потребовался полиморфизм в этой ситуации.
> После этого создадим 2 модели: Customer и Executive. В миграциях можно прописать любые уникальные для каждого типа пользователя данные
В описанном в статье примере очень не хватает этих самых миграций с любыми уникальными для каждого типа пользователя данными. Без них получается что все ради поля character, а его можно было завести и без всякого полиморфизма.
И еще не ясно откуда взялся метод «admin?». Cancan его сам как-то определяет?
> После этого создадим 2 модели: Customer и Executive. В миграциях можно прописать любые уникальные для каждого типа пользователя данные
В описанном в статье примере очень не хватает этих самых миграций с любыми уникальными для каждого типа пользователя данными. Без них получается что все ради поля character, а его можно было завести и без всякого полиморфизма.
И еще не ясно откуда взялся метод «admin?». Cancan его сам как-то определяет?
Прошу прощения, admin? пролез случайно, недосмотрел :(
По поводу уникальных полей — у исполнителя эти поля icq, skype, email (публичный),
а у заказчика — ИНН, название фирмы, адрес фирмы, город проживания и что-то еще.
+ такая модель позволяет прописывать ассоциации непосредственно в моделях. То есть в executive.rb мы напишем:
has_many :participations, :dependent => :destroy
has_many :documents, :through => :participations
А в customer.rb:
has_many :documents, :dependent => :destroy
Таким образом, и заказчики, и исполнители связаны с документами. У обоих типов пользователей мы можем написать user.documents, но вот выбираться они будут по-разному. То есть для заказчика «свои документы» — это те, которые он написал, а для исполнителя — те, к которым он подключился (или же его подключили).
По поводу уникальных полей — у исполнителя эти поля icq, skype, email (публичный),
а у заказчика — ИНН, название фирмы, адрес фирмы, город проживания и что-то еще.
+ такая модель позволяет прописывать ассоциации непосредственно в моделях. То есть в executive.rb мы напишем:
has_many :participations, :dependent => :destroy
has_many :documents, :through => :participations
А в customer.rb:
has_many :documents, :dependent => :destroy
Таким образом, и заказчики, и исполнители связаны с документами. У обоих типов пользователей мы можем написать user.documents, но вот выбираться они будут по-разному. То есть для заказчика «свои документы» — это те, которые он написал, а для исполнителя — те, к которым он подключился (или же его подключили).
По моему вместо
в третьих рельсах надо писать
Спасибо за интересную статью.
validates_presence_of :name, :character_type
в третьих рельсах надо писать
validates :name, :character_type, :presence => true
Спасибо за интересную статью.
Ну, это уже дело вкуса, хотя я предпочитаю вариант с параметром-типом валидации, который был введен в 3 версии.
не учите плохому, лучше исправьте, т.к. в 3.1 эти методы уже будут удалены.
сорри, не туда ответил.
так я же и написал, что предпочитаю новый синтаксис:
validates :name, :character_type, :presence => true
Просто некоторым людям удобнее или привычнее использовать старый. Кстати, в одной из книг по Rails 3, если не ошибаюсь, авторства Оби Фернандеса, используется как раз-таки старый синтаксис.
validates :name, :character_type, :presence => true
Просто некоторым людям удобнее или привычнее использовать старый. Кстати, в одной из книг по Rails 3, если не ошибаюсь, авторства Оби Фернандеса, используется как раз-таки старый синтаксис.
Да, уже отметили, что можно и так, и так. Я пока что себя на новый лад не переучил (и сниппеты текстмейта тоже =).
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Полиморфные ассоциации и Devise в Ruby on Rails