Как да създам множество бутони за изпращане за един и същ формуляр в Rails?

Трябва да имам няколко бутона за изпращане.

Имам формуляр, който създава екземпляр на Contact_Call.

Един бутон го създава както обикновено.

Другият бутон го създава, но трябва да има различна стойност :attribute от стойността по подразбиране и също така трябва да зададе атрибута на различен, но свързан модел, използван в контролера.

Как да направя това? Не мога да променя маршрута, така че има ли начин да изпратя различна променлива, която да бъде приета от [:params]?

И ако го направя тогава, какво да направя в контролера, да настроя отчет за случай?


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
Промяната на атрибута за действие на формата в движение е по-крехко решение. Използването на атрибута commit е по-малко. Като алтернатива бихте могли да обвиете втория бутон за изпращане в различен формуляр и да подадете параметър, който трябва да бъде променен на същото действие. Но не е много по-различно от разчитането на стойностите на 2 бутона за изпращане. Без да знаете повече как сте настроили това нещо, най-доброто решение досега би било с 2 бутона за изпращане. - person Anurag; 12.06.2010
comment
добре добре... добре съм с това, просто исках да знам, ще експериментирам с него, надявам се днес и ще ви уведомя! - person Satchel; 17.06.2010
comment
Благодаря много! Беше наистина много полезно!! - person Maddy; 27.02.2012
comment
Анураг, ти си страхотен! Благодаря много!! - 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

Има и друг подход, използващ атрибута formation на бутона за изпращане:

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

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

formation:
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[: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, защото се показва стойност и ако показвате Unicode знаци, това ще стане объркващо. - person xji; 04.03.2015
comment
Параметрите обаче не се допускат. Използвам simple_form gem. Има ли някаква корелация. - person xji; 05.03.2015
comment
Това не отделя изгледа от контролера, но поне отделя текста, показван от контролера. много по-добър IMO. - person Mic Fok; 23.03.2015
comment
подобен проблем на Xiang Ji. Използвам 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?, който връща true, ако параметърът за ангажиране съвпада с дадения 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