Как мне создать несколько кнопок отправки для одной и той же формы в Rails?

Мне нужно иметь несколько кнопок отправки.

У меня есть форма, которая создает экземпляр Contact_Call.

Одна кнопка создает его как обычно.

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

Как я могу это сделать? Я не могу изменить маршрут, так есть ли способ отправить другую переменную, которую подбирает [: params]?

И если я это сделаю, что мне делать в контроллере, настроить оператор case?


person Satchel    schedule 12.06.2010    source источник
comment
возможный дубликат Rails: кнопки множественной отправки в одной форме   -  person Joshua Pinter    schedule 22.06.2015
comment
Этот старше и набрал больше голосов. Во всяком случае, вышеперечисленное должно быть закрыто как дубликат этого ...   -  person Taryn East    schedule 23.06.2015


Ответы (7)


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

<% form_for(something) do |f| %>
    ..
    <%= f.submit 'A' %>
    <%= f.submit 'B' %>
    ..
<% end %>

Это выведет:

<input type="submit" value="A" id=".." name="commit" />
<input type="submit" value="B" id=".." name="commit" />

Внутри вашего контроллера отправленное значение кнопки будет идентифицировано параметром commit. Отметьте значение, чтобы выполнить необходимую обработку:

def <controller action>
    if params[:commit] == 'A'
        # A was pressed 
    elsif params[:commit] == 'B'
        # B was pressed
    end
end

Однако помните, что это тесно связывает ваш взгляд с контроллером, что может быть не очень желательно.

person Anurag    schedule 12.06.2010
comment
Теперь это что-то новенькое. Спасибо @Anurag! - person Shripad Krishna; 12.06.2010
comment
так что просто поставив 'A' автоматически создаст параметр name = 'commit'? - person Satchel; 12.06.2010
comment
есть ли способ, как вы сказали, не связывать представление с контроллером жестко? например, для кнопок отправки изменить URL-адрес? кажется, что это не обязательно плохо, потому что форма отправляет переменные, которые могут изменить поведение контроллера, даже если это пользовательский ввод, каков выбор кнопки? - person Satchel; 12.06.2010
comment
Вы не можете изменить атрибут действия формы без грязного взлома js. - person Ben Orozco; 12.06.2010
comment
Изменение атрибута действия формы «на лету» - более хрупкое решение. Использование атрибута фиксации менее актуально. В качестве альтернативы вы можете заключить вторую кнопку отправки в другую форму и передать параметр, который необходимо изменить на то же действие. Но это не сильно отличается от значений двух кнопок отправки. Не зная больше, как вы настроили эту штуку, лучшим решением пока будет использование двух кнопок отправки. - person Anurag; 12.06.2010
comment
хорошо, хорошо ... Я в порядке с этим, просто хотел знать, поэкспериментирую с этим, надеюсь сегодня и дам вам знать! - person Satchel; 17.06.2010
comment
Благодаря тонну! Это было действительно полезно !! - person Maddy; 27.02.2012
comment
Anurag, ты классный! Большое спасибо!! - person uday; 27.02.2012
comment
Может быть, кто-нибудь может помочь мне с этой проблемой stackoverflow.com/questions/18476292/ - person John Smith; 28.08.2013
comment
А как насчет проблем с i18n? - person Nicolas Garnil; 18.10.2013
comment
Следует использовать f.button помощник. Он использует элемент <button>, который позволяет иметь отдельные value и заголовок. - person urmurmur; 21.07.2015
comment
Я считаю, что stackoverflow.com/a/3333426/1067145 - более чистый подход. Лучше установить внеполосное «имя» отправки, чем проверять само значение. - person Max Wallace; 07.06.2016
comment
Я думаю, что решение @patpit ниже - лучший подход! Используйте атрибут formaction на кнопке отправки, чтобы перезаписать URL-адрес, на который была отправлена ​​форма. - person mrcasals; 18.05.2020

Существует также другой подход, использующий атрибут formaction на кнопке отправки:

<% form_for(something) do |f| %>
    ...
    <%= f.submit "Create" %>
    <%= f.submit "Special Action", formaction: special_action_path %>
<% end %>

Код остается чистым, поскольку стандартная кнопка создания не требует никаких изменений, вы только вставляете путь маршрутизации для специальной кнопки:

formaction:
URI программы, которая обрабатывает информацию, отправленную элементом ввода, если это кнопка отправки или изображение. Если указано, он переопределяет атрибут действия владельца формы элемента. Источник: MDN.

person patpir    schedule 12.09.2015
comment
это поддерживается во всех браузерах. w3schools.com/tags/att_button_formaction.asp w3schools.com/tags/att_input_formaction.asp - person Sumit Garg; 13.05.2016
comment
Я понимаю, что вопрос старый, но я советую читателям, что это краткое решение заслуживает более внимательного рассмотрения. - person Jerome; 12.11.2016
comment
Хотел бы я найти этот ответ в первый раз, когда у меня возник тот же вопрос. Я рад, что на этот раз решил заглянуть глубже. Отличное решение. - person rockusbacchus; 24.08.2017
comment
Мне очень нравится это решение. Однако мне пришлось добавить скрытое поле с токеном CSRF, хотя я уже использовал помощники форм, иначе Rails не примет токен. Я не смог найти лучшего обходного пути и до сих пор не уверен, почему именно это происходит, или просто добавление токена исправляет это. - person irruputuncu; 10.06.2020
comment
Я думаю, что это лучшее решение, потому что оно уважает принципы единой ответственности и сохраняет ясность, каждая кнопка выполняет свое собственное действие, сохраняя логику в контроллерах простой. - person Khalil Gharbaoui; 09.07.2020

Вы также можете узнать, какая кнопка была нажата, изменив имя ее атрибута.

<% form_for(something) do |f| %>
    ..
    <%= f.submit 'A', name: 'a_button' %>
    <%= f.submit 'B', name: 'b_button' %>
    ..
<% end %>

Это немного неудобно, потому что вам нужно проверять наличие ключей params, а не просто проверять значение params[:commit]: вы получите params[:a_button] или params[:b_button] в зависимости от того, какой из них был нажат.

person masciugo    schedule 22.04.2013
comment
По-прежнему не отделяет вид от контроллера. - person slowpoison; 26.05.2013
comment
Да, если разделение означает отказ от некоторой логики в действии, чтобы перейти к последнему действию, вы правы, они все равно связаны. Я просто имел в виду, что если вы используете атрибут name в этой логике, ваш контроллер не зависит от того, что показано на кнопке. Спасибо, отредактировал - person masciugo; 29.05.2013
comment
Этот вариант кажется лучше, чем принятый в ситуациях i18n, потому что отображается значение, и если вы показываете символы Юникода, оно может стать беспорядочным. - person xji; 04.03.2015
comment
Однако параметры не пропускаются. Я использую гем simple_form. Есть ли корреляция. - person xji; 05.03.2015
comment
Это не отделяет представление от контроллера, но, по крайней мере, отделяет отображаемый текст от контроллера. намного лучше IMO. - person Mic Fok; 23.03.2015
comment
аналогичная проблема с Сян Цзи. Я использую form_tag, а параметр не проходит - person ryan2johnson9; 17.12.2015

Решение, аналогичное предложенному @ vss123, без использования драгоценных камней:

resources :plan do
  post :save, constraints: lambda {|req| req.params.key?(:propose)}, action: :propose
  post :save, constraints: lambda {|req| req.params.key?(:finalize)}, action: :finalize
end

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

person Tadas Sasnauskas    schedule 19.03.2014

Мы решили использовать дополнительные ограничения в рельсах.

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

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

CommitParamRouting - это простой класс, у которого есть метод matches?, который возвращает истину, если параметр фиксации совпадает с данным экземпляром attr. ценить.

Это доступно как гем commit_param_matching.

person siliconsenthil    schedule 27.10.2013

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

class SearchController < ApplicationController
  SEARCH_TYPES = {
    :searchABC => "Search ABCs",
    :search123 => "Search 123s"
  }

  def search
    [...]
    if params[:commit] == SEARCH_TYPES[:searchABC]
      [...]
    elsif params[:commit] == SEARCH_TYPES[:search123]
      [...]
    else
      flash[:error] = "Search type not found!"]
      [...]
    end
  end
  [...]          
end

А потом в представлении:

<% form_for(something) do |f| %>
    [...]
    <%= f.submit SearchController::SEARCH_TYPES[:searchABC] %>
    <%= f.submit SearchController::SEARCH_TYPES[:search123] %>
    [...]
<% end %>

Таким образом, текст находится только в одном месте - как константа в контроллере. Однако я еще не пытался понять, как это сделать.

person Draknor    schedule 24.07.2014
comment
Что вы имеете в виду под i18n? - person skrrgwasme; 25.07.2014
comment
Было ли это предпочтительнее использования ограничений в маршруте? Спасибо! - person Satchel; 26.07.2014
comment
@Scott: i18n означает «интернационализация» - в основном, как бы вы поддерживали несколько языков. Я на самом деле не изучал это, поэтому я не очень хорошо знаком с тем, как это работает или как его реализовать. - person Draknor; 14.08.2014
comment
@Angela - наверное, нет :) И на самом деле, после рефакторинга моего кода я просто создал несколько форм, каждая с разными действиями, а не одну монолитную форму, содержащую кучу несвязанных форм. - person Draknor; 14.08.2014

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

person Shawn Walton    schedule 19.04.2016