Как стать автором
Обновить

Полиморфные связи. Маленькое дополнение

Время на прочтение3 мин
Количество просмотров1.3K
В декабре на Хабре была хорошая статья, о полиморфных связях в Рельсах. Вот она. Перед тем как читать дальше, пожалуйста ознакомьтесь с ней.
Однако, у автора статьи осталось несколько неотвеченных вопросов. Вот на них то мы сегодня и найдем ответы.


Во первых, в тексте статьи присутствует вот такой код.

  1. module PostsHelper
  2. def posts_smth_path(post)
  3. case post.content.class.to_s.downcase
  4. when "topic" : posts_topic_path(post)
  5. when "link" : posts_link_path(post)
  6. when "podcast" : posts_podcast_path(post)
  7. end
  8. end
  9. def posts_smths_path(post)
  10. case post.content.class.to_s.downcase
  11. when "topic" : posts_topics_path
  12. when "link" : posts_links_path
  13. when "podcast" : posts_podcasts_path
  14. end
  15. end
  16. end


Он конечно же работает, но… это ведь совершенно не стиль Rails. Всё должно быть проще. Так и есть. Рельсы предлагают нам отличный вариант — метод polymorphic_path (). А также new_polymorphic_path () и edit_polymorphic_path (). Суть метода, а в том, что он в зависимости от того, какие модели в него подаются, будет выдавать нужные нам урлы. Вот так.

  1. <% if can? :edit, @post %>
  2. <%= link_to "Edit this #{@post.content.class.to_s.downcase}", edit_polymorphic_path([:posts, @post.content]), :class => "b-post-edit_link g-link-no-visited" %>
  3. <% end %>


Здесь, в зависимости от того, какой именно content у @post (Topic, Link, Podcast), будет подставляться url для его редактирования. Понятно, что polymorphic_path () и new_polymorphic_path () работают аналогично.

Во-вторых, автору по ходу статьи подсказали, что неплохо было бы использовать accepts_nested_attributes_for и даже потом сделали статью на эту тему, но вот как это сочитается с полиморфными связями, в статье не написано. А сочитается это очень хорошо, главное подход знать:)

Давайте для примера расмотрим контроллер, который будет создавать Topic.

  1. class Posts::TopicsController < PostsController
  2. def index
  3. @posts = Post.topics.find(:all)
  4. end
  5. def new
  6. @topic = Topic.new
  7. @topic.build_post
  8. @selectable_categories = Category.all.collect{ |c| [c.title, c.id] }
  9. end
  10. def edit
  11. @topic = Topic.find(params[:id])
  12. @post = @topic.post
  13. @selectable_categories = Category.all.collect{ |c| [c.title, c.id] }
  14. end
  15. def create
  16. @topic = Topic.new(params[:topic])
  17. @topic.post.author = current_user
  18. if @topic.save
  19. redirect_to post_path(@topic.post)
  20. else
  21. @selectable_categories = Category.all.collect{ |c| [c.title, c.id] }
  22. render :action => "new"
  23. end
  24. end
  25. def update
  26. @topic = Topic.find(params[:id])
  27. if @topic.update_attributes(params[:topic])
  28. redirect_to post_path(@topic.post)
  29. else
  30. @selectable_categories = Category.all.collect{ |c| [c.title, c.id] }
  31. render :action => "edit"
  32. end
  33. end
  34. end



Видим, что всё очень легко. И самое главное — это работает. Рабочий прмер всего этого можно посмотреть вот тут.

P.S. Для всех, кто программирует на Рельсе, посмотрите мою вчерашнюю ссылку на Хабре. Очень интересные вещи о ActiveRecord в Rails 3.

UPD. Забыл ещё одну маленькую деталь. Для удобства редактирования и легкой масштабируемости можно ещё соответствующим образом допились вьюху. Пример вот тут (тут я её не хочу выкладывать, потому что слишком много кода будет). По ссылке файл с вьюхой для Post, из которого в зависости от типа content дергается вьюха для Topic или Link.
Теги:
Хабы:
+25
Комментарии6

Публикации

Истории

Работа

Ruby on Rails
11 вакансий

Ближайшие события