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

98

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

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

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

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

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

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

Тимоти Т.
источник
возможный дубликат Rails: кнопки множественной отправки в одной форме
Джошуа Пинтер
3
Этот старше и набрал больше голосов. Во всяком случае, вышеизложенное должно быть закрыто как дубликат этого ...
Taryn East

Ответы:

129

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

<% 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

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

Анураг
источник
1
Теперь это что-то новенькое. Спасибо @Anurag!
Shripad Krishna
1
так что просто поставив 'A' автоматически создаст параметр name = 'commit'?
Тимоти Т.
есть ли способ, как вы сказали, не связывать представление с контроллером жестко? например, для кнопок отправки изменить URL-адрес? Это кажется , что это не обязательно плохо , так как форма передает переменные , которые могут изменить поведение контроллера Hte, д аже если это пользовательский ввод, который выбор кнопки есть?
Тимоти Т.
1
Вы не можете изменить атрибут действия формы без грязного взлома js.
Бен Ороско,
Изменение атрибута действия формы «на лету» - более хрупкое решение. Использование атрибута фиксации менее актуально. В качестве альтернативы вы можете заключить вторую кнопку отправки в другую форму и передать параметр, который необходимо изменить на то же действие. Но это не сильно отличается от значений двух кнопок отправки. Не зная больше, как вы настроили эту штуку, лучшим решением пока будет использование двух кнопок отправки.
Anurag
75

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

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

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

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

патпир
источник
2
это поддерживается во всех браузерах. w3schools.com/tags/att_button_formaction.asp w3schools.com/tags/att_input_formaction.asp
Sumit Garg
8
Я понимаю, что вопрос старый, но я советую читателям, что это краткое решение заслуживает более внимательного рассмотрения.
Джером
2
Хотел бы я найти этот ответ в первый раз, когда у меня возник тот же вопрос. Я рад, что на этот раз решил посмотреть немного глубже. Отличное решение.
rockusbacchus
1
Мне очень нравится это решение. Однако мне пришлось добавить скрытое поле с токеном CSRF, хотя я уже использовал помощники форм, иначе Rails не примет токен. Я не смог найти лучшего обходного пути, и до сих пор не уверен, почему именно это происходит, или просто добавление токена исправляет это.
irruputuncu,
Я думаю, что это лучшее решение, потому что оно уважает принципы единой ответственности и сохраняет ясность, каждая кнопка выполняет свое собственное действие, сохраняя логику в контроллерах простой.
Халил Гарбауи,
29

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

<% 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]зависимости от того, какой из них был нажат.

Masciugo
источник
2
По-прежнему не отделяет вид от контроллера.
slowpoison
1
Да, если разделение означает отказ от некоторой логики в действии, чтобы перейти к окончательному действию, вы правы, они все равно связаны. Я просто имел в виду, что если вы используете атрибут name в этой логике, ваш контроллер не зависит от того, что показано на кнопке. Спасибо, отредактировал
masciugo
4
Этот вариант кажется лучше, чем принятый в ситуациях i18n, потому что отображается «значение», и если вы показываете символы Юникода, это будет беспорядочно.
xji
2
Однако параметры не пропускаются. Я использую гем simple_form. Есть ли корреляция.
xji 05
1
Это не отделяет представление от контроллера, но, по крайней мере, отделяет отображаемый текст от контроллера. намного лучше IMO.
Mic Fok
13

Решение, аналогичное предложенному @ 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

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

Тадас Саснаускас
источник
9

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

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

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 .

кремний
источник
3

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

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 %>

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

Дракнор
источник
Что вы имеете в виду под «i18n»?
skrrgwasme
Было ли это предпочтительнее использования ограничений в маршруте? Спасибо!
Timothy T.
@Scott: i18n означает «интернационализация» - в основном, как бы вы поддерживали несколько языков. Я на самом деле не изучал это, поэтому я не очень хорошо знаком с тем, как это работает или как его реализовать.
Draknor
@Angela - вероятно, нет :) И на самом деле, после рефакторинга моего кода я просто создал несколько форм, каждая с разными действиями, а не одну монолитную форму, содержащую кучу несвязанных форм.
Draknor
1

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

Шон Уолтон
источник