Як створити кілька кнопок надсилання для однієї форми в Rails?


97

Мені потрібно мати кілька кнопок подання.

У мене є форма, яка створює екземпляр Contact_Call.

Одна кнопка створює її як звичайну.

Інша кнопка створює його, але має мати інше: значення атрибута за замовчуванням, а також йому потрібно встановити атрибут для іншої, але пов’язаної моделі, що використовується в контролері.

Як це зробити? Я не можу змінити маршрут, тож чи є спосіб надіслати іншу змінну, яку отримує [: params]?

І якщо я тоді, що робити в контролері, налаштувати випадок справи?


можливий дублікат Rails: Кнопки
Джошуа Пінтер

3
Цей старший і має більше голосів. Якщо що, вищезазначене слід закрити як копію цього ...
Тарін Іст

Відповіді:


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!
Шріпад Кришна

1
так що просто ставлячи 'A' автоматично створює параметр name = 'commit'?
Тімоті Т.

чи є спосіб, як ви сказали, не щільно поєднати вигляд з контролером? наприклад, щоб кнопки подання змінили URL-адресу? Це здається , що це не обов'язково погано , так як форма передає змінні , які можуть змінити поведінку контролера Hte, д аже якщо це для користувача введення, який вибір кнопки є?
Тімоті Т.

1
Ви не можете змінити атрибут дії форми без брудного js-злому.
Бен Ороско,

Зміна атрибута дії форми на льоту є більш крихким рішенням. Використання атрибута коміту - це менше. Як альтернативу ви можете обернути другу кнопку подання в іншу форму і передати параметр, який потрібно змінити на ту саму дію. Але це мало чим відрізняється від сподівання на значення двох кнопок подання. Не знаючи більше, як ви налаштували цю річ, найкращим рішенням на сьогоднішній день буде 2 кнопки подання.
Анураг

74

Існує також інший підхід, який використовує атрибут formation на кнопці submit:

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

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

формація:
URI програми, яка обробляє інформацію, подану елементом введення, якщо це кнопка подання або зображення. Якщо вказано, він замінює атрибут дії власника форми елемента . Джерело: MDN


2
це підтримується у всіх браузерах w3schools.com/tags/att_button_formaction.asp w3schools.com/tags/att_input_formaction.asp
Гарг

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]залежно від того, який з них було натиснуто.


2
Досі не відокремлює вид від контролера.
slowpoison

1
Так, якщо відокремлення означає уникання певної логіки в дії для того, щоб перейти до остаточної дії, ви маєте рацію, вони все одно поєднані. Я просто мав на увазі, що якщо ви використовуєте атрибут name у цій логіці, ваш контролер не залежить від того, що показано на кнопці. Спасибі, відредаговано
masciugo

4
Цей, здається, кращий за прийнятий у ситуаціях i18n, оскільки відображається "значення", і якщо ви відображаєте символи Unicode, це буде брудно.
xji

2
Однак параметри не пропускаються. Я використовую самоцвіт simple_form. Чи існує якась кореляція.
xji

1
Це не роз'єднує подання з контролера, але принаймні роз'єднує текст, що відображається з контролера. набагато краще IMO.
Мік Фок

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. значення.

Це доступно як gem 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 означає "інтернаціоналізація" - в основному, як би ви підтримували кілька мов. Я насправді не вивчав це, тому я не дуже обізнаний у тому, як це працює або як його реалізувати.
Дракнор

@Angela - мабуть, ні :) І насправді, після рефакторингу мого коду я просто створив кілька форм, кожна з різними діями, а не єдину монолітну форму, що містила купу не пов'язаних між собою форм.
Дракнор

1

У мене у формі є змінна кількість кнопок надсилання завдяки nested_form_fields, тож просто використання імені мені було недостатньо. Врешті-решт, я включив приховане поле введення у форму та використовую Javascript для заповнення, коли натиснуто одну з кнопок подання форми.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.