Рельсы: несколько кнопок отправки в одной форме


скажем, у меня есть модель статьи, и в представлении статьи "Новый" у меня есть две кнопки: "Опубликовать"и" сохранить Черновик".

мой вопрос в том, как я могу узнать, какая кнопка нажата в контроллере.

у меня уже есть решение, но я думаю, что там должен быть лучший способ. Что я в настоящее время используется в вид:

<div class="actions">
  <%= f.submit "Publish" %>
  <%= f.submit "Save Draft", :name => "commit" %>
</div>

Так в контроллере, я могу использовать params [: commit] строку для обработки этого действия.

def create
  @article = Article.new(params[:article])
  if params[:commit] == "Publish"
    @article.status = 'publish'
    // detail omitted
  end

  @article.save
end

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

обновление: так как эти кнопки находятся в той же форме, они все собираются в действие "создать", и это нормально для меня. Я хочу обработать это в действии create, например, дать модели статьи столбец "статус" и содержит "public" или "черновик".

6 54

6 ответов:

Это было написано в Railscast эпизод 38. Используя params хэш, чтобы определить, какая кнопка была нажата правильный подход:

View:

<%= submit_tag 'Create' %>
<%= submit_tag 'Create and Add Another', name: 'create_and_add' %>

:

if params[:create_and_add]
  # Redirect to new form, for example.

else
  # Redirect to show the newly created record, for example.
end

мы решили с помощью дополнительные ограничения в рельсы.

идея состоит в том, чтобы иметь один и тот же путь (и, следовательно, одно и то же имя route & action), но с ограничениями маршрутизации на разные действия.

resources :plan do
  post :save, constraints: CommitParamRouting.new("Propose"), action: :propose
  post :save, constraints: CommitParamRouting.new("Finalize"), action: :finalize
end

CommitParamRouting - Это простой класс, который имеет метод matches? который возвращает true, если параметр commit соответствует данному экземпляру attr. значение.

Это доступно как драгоценный камень commit_param_matching.

Он также может быть сделано на form_for помощник такой

 <%= f.submit "Publish",name: "publish", class: "tiny button radius success" %>
 <%= f.submit 'Mark as Draft', name: "draft", class: "tiny button radius " %>

и логика та же на контроллере

   if params[:publish]
      // your code
   elsif params[:draft]
      // your code
   end

Я помню, как однажды столкнулся с этой проблемой. Вы не можете сохранить две кнопки, а затем вызвать какое-либо действие на основе параметров[:commit]. кнопка отправки onclick будет вызывать url-адрес, на который ссылается форма. Есть определенные плохие способы получить желаемое поведение. Держите кнопку для вызова действия, на которое ссылается форма, и чтобы получить другую кнопку для вызова действия, я использовал link_to, а затем изменил стили, чтобы соответствовать кнопке. Кроме того, в качестве альтернативы вы можете использовать jQuery для изменения url-адреса формы вызов, следовательно, решая, какое действие вызывается во время выполнения. Надеюсь, это поможет.

вы также можете установить некоторые data атрибуты на кнопках отправки и использовать JavaScript, чтобы изменить form действие при нажатии одной из кнопок

обычно я использую предложение, данное Джоном Топли (см. ответ выше). другим способом является использование jQuery / JS изменение атрибута действия формы-при нажатии кнопки " Отправить пример:

form_tag({} ,:method => 'post', :id => 'reports_action') do 
   .......
   ....... 
  submit_tag 'submit',  :onclick => "return changeAction();"
end

и потом .....

function changeAction(){
   $('#reports_action').attr('action','my_new_action');
}