Маршрутизация для нескольких контроллеров для одного ресурса в Rails 3.1 - PullRequest
0 голосов
/ 27 сентября 2011

Я задал вопрос, похожий на этот, около недели назад, но это немного другая точка зрения. Суть вопроса заключается в том, чтобы быть перенаправленным на правильный контроллер.

У меня есть один ресурс, посты, и у меня есть 4 разные категории, в которых эти посты могут быть. Я хочу, чтобы каждая из этих категорий относилась к одному контроллеру, и поэтому у меня в маршрутах есть следующее:

resources "code", :controller => :code_posts, :as => :code
resources "sports", :controller => :sports_posts, :as => :sports
resources "gaming", :controller => :game_posts, :as => :gaming
resources "the-nation", :controller => :personal_posts, :as => :the_nation

Так что теперь я могу получить доступ к сообщениям через URL-адреса, такие как, например, / code / 1, / sports / 34, чтобы получить доступ к одному и тому же ресурсу сообщений, но каждый контроллер фокусируется на одной области, а именно на определенной категории.

Это все хорошо, но моя проблема возникает, когда я пытаюсь редактировать или сохранять определенные сообщения. У меня есть следующий частичный _form.html.erb (отображается в новых и редактируемых представлениях) во всех папках представлений для их конкретного контроллера:

<%= form_for @post do |f| %>
<div class="field">
  <%= f.label :author %><br/>
  <%= f.text_field :author %>
</div>
<div class="field">
    <%= f.label :title %><br/>
    <%= f.text_field :title %>
</div>
<div class="field">
  <%= f.label :category %>
  <%= f.select :category_id, Category.all.collect {|c| [c.name, c.id] }, {:include_blank => true} %>
</div>
<div class="field">
  <%= f.label :summary %><br/>
  <%= f.text_area :summary, :rows => 5 %>
</div>
<div class="field">
  <%= f.label :body %><br/>
  <%= f.text_area :body %>
</div>
<div class="field">
  <%= f.label :tag_tokens %><br/>
  <%= f.text_field :tag_tokens, "data-pre" => @post.tags.map(&:attributes).to_json %>
</div>
<div class="field">
    <%= f.submit "Submit" %>
</div>
<% end %>

Так что всякий раз, когда я создаю или обновляю сообщение с помощью любых контроллеров, меня всегда перенаправляют обратно на / posts / 4, / posts / 123, / posts /: id, что угодно. Я хочу, чтобы меня перенаправили на конкретный контроллер, под которым редактируется или создается пост. Поэтому, если я перехожу в / code / new и отправляю новое сообщение, я хочу, чтобы меня перенаправили в / code / 1234, а не в / posts / 1234. Как я могу это сделать? По какой-то причине у меня сегодня утром серьезные проблемы с психикой. Спасибо.

РЕДАКТИРОВАТЬ Обновлено <%= form_for @post do |f| %> до <%= form_for @post, :url => code_url(@post) do |f| %>, и это работает для / code / 1 / edit, но не / code / new. При попытке получить доступ к новой форме сообщения, я получаю следующую ошибку:

No route matches {:action=>"show", :controller=>"code_posts", :id=>#<Post id: nil, author: "Les Peabody", summary: nil, body: nil, created_at: nil, updated_at: nil, title: nil, category_id: 1, slug: nil>}

Это мой CodePostsController # новый метод

def new
  @post = Post.new(:category => Category.find_by_name("Programming"), :author => current_user.full_name)
end

Ответы [ 3 ]

0 голосов
/ 27 сентября 2011

Вы можете указать URL в форме

<% = form_for @post,: url => gaming_path do | f | %>

Вы можете использовать наследование в модели. Путь в вашей форме определяется именем класса, и в данном случае это пост. Если они работают с именами ресурсов, они также должны генерировать правильные пути.

Грязный хак может держать путь объектов в нем, я видел, как кто-то делает это, но я не очень рекомендую это.

0 голосов
/ 28 сентября 2011

Итак, в конечном итоге важно то, как форма превращается в HTML. Если вы посмотрите на различия между формой, предназначенной для редактирования, и формой, предназначенной для нового объекта, есть только одна вещь, которая действительно сильно отличается, - URL действия.

В случае новой формы тег формы должен выглядеть примерно так:

<form accept-charset="UTF-8" action="/code" class="new_post" id="new_post" method="post">

и в случае формы редактирования:

<form accept-charset="UTF-8" action="/code/1" class="edit_post" id="edit_post_1" method="post">

Однако единственное, что имеет значение для рельсов, это имя входных элементов (которые являются постоянными в обеих формах) и атрибут action в теге формы. Это сообщает Rails, рендерит ли он действие редактирования или создания.

Поскольку мы разделяем контроль над одним ресурсом через несколько контроллеров, стандарт form_for @post не будет достаточным, поскольку Rails больше не может автоматизировать процесс рендеринга с помощью соглашения (поскольку мы делаем очень нетрадиционную вещь). Надо заниматься физическим трудом. Следующее поможет.

Преобразовать частичное в следующее:

<%= form_for @post, :url => path do |f| %>
<div class="field">
  <%= f.label :author %><br/>
  <%= f.text_field :author %>
</div>
<div class="field">
    <%= f.label :title %><br/>
    <%= f.text_field :title %>
</div>
<div class="field">
  <%= f.label :category %>
  <%= f.select :category_id, Category.all.collect {|c| [c.name, c.id] }, {:include_blank => true} %>
</div>
<div class="field">
  <%= f.label :summary %><br/>
  <%= f.text_area :summary, :rows => 5 %>
</div>
<div class="field">
  <%= f.label :body %><br/>
  <%= f.text_area :body %>
</div>
<div class="field">
  <%= f.label :tag_tokens %><br/>
  <%= f.text_field :tag_tokens, "data-pre" => @post.tags.map(&:attributes).to_json %>
</div>
<div class="field">
    <%= f.submit "Submit" %>
</div>
<% end %>

Переменная path, в которой есть переменная, переданная через механизм: locals при частичном рендеринге, например:

new.html.erb

<%= render :partial => "form", :locals => {:path => code_index_path} %>

и edit.html.erb

<%= render :partial => "form", :locals => {:path => code_path(@post)} %>

Приятно, что с этим решением вы можете также высушить код, поместив _form.html.erb в app / views / layouts или app / views / posts и повторно использовать его во всех новых и редактировать представления для всех контроллеров, которые последовательно управляют ресурсом Post. Так что вместо:

<%= render :partial => "form", :locals => {:path => code_path(@post)} %>

у нас есть:

<%= render :partial => "layouts/form", :locals => {:path => code_path(@post)} %>
0 голосов
/ 27 сентября 2011

Я думаю, что причина в методе form_for, который принимает за действие обновления по умолчанию имя параметра (здесь post), который он получает.

Таким образом, чтобы изменить это, вы должны добавитьв начале (для примера ресурса code) следующее:

<%= form_for @post, :url => code_path(@post) do |f| %>

Это, конечно, только URL для существующего объекта, URL для нового объекта должен быть другим.Там должно быть new_code_path (и без аргументов).Таким образом, ваш частичный должен содержать только поля и метки, а не вызов form_for, потому что URL должен отличаться от этого.

Вы должны посмотреть на вывод вызова в оболочке: bundle exec rake routes и выполнить поискдля правильных путей в выводе.

...