Làm cách nào để tạo nhiều nút gửi cho cùng một biểu mẫu trong Rails?


97

Tôi cần có nhiều nút gửi.

Tôi có một biểu mẫu tạo một phiên bản của Contact_Call.

Một nút tạo nó như bình thường.

Nút khác tạo ra nó nhưng cần có giá trị thuộc tính: khác với giá trị mặc định và nó cũng cần đặt thuộc tính trên một mô hình khác nhưng có liên quan được sử dụng trong bộ điều khiển.

Làm thế nào để làm điều đó? Tôi không thể thay đổi lộ trình, vậy có cách nào để gửi một biến khác được chọn bởi [: params] không?

Và nếu tôi làm vậy thì tôi phải làm gì trong bộ điều khiển, thiết lập một câu lệnh tình huống?



3
Cái này cũ hơn và có nhiều phiếu bầu hơn. Nếu bất cứ điều gì ở trên nên được đóng lại như một bản sao của này ...
Taryn Đông

Câu trả lời:


129

Bạn có thể tạo nhiều nút gửi và cung cấp một giá trị khác nhau cho mỗi:

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

Điều này sẽ xuất ra:

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

Bên trong bộ điều khiển của bạn, giá trị của nút đã gửi sẽ được xác định bằng tham số commit. Kiểm tra giá trị để thực hiện xử lý bắt buộc:

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

Tuy nhiên, hãy nhớ rằng điều này kết hợp chặt chẽ giữa chế độ xem của bạn với bộ điều khiển, điều này có thể không được mong muốn cho lắm.


1
Bây giờ đó là một cái gì đó mới. Cảm ơn @Anurag!
Shripad Krishna

1
vì vậy chỉ cần đặt 'A' tự động tạo tên tham số = 'cam kết'?
Timothy T.

Có cách nào như bạn đã nói không để kết hợp chặt chẽ giữa chế độ xem với bộ điều khiển? ví dụ, cho các nút gửi để thay đổi URL? Có vẻ như điều này không nhất thiết là xấu bởi vì biểu mẫu gửi các biến có thể thay đổi hành vi của bộ điều khiển hte, e ven nếu nó là người dùng nhập, lựa chọn của nút là gì?
Timothy T.

1
Bạn không thể thay đổi thuộc tính hành động biểu mẫu nếu không có một bản hack js lộn xộn.
Ben Orozco

Thay đổi thuộc tính hành động biểu mẫu ngay lập tức là một giải pháp dễ hiểu hơn. Sử dụng thuộc tính cam kết ít hơn. Thay vào đó, bạn có thể bọc nút gửi thứ hai bên trong một biểu mẫu khác và chuyển một tham số cần được thay đổi thành hành động tương tự. Nhưng nó không khác nhiều so với việc dựa vào giá trị của 2 nút gửi. Nếu không biết thêm về cách bạn đã thiết lập điều này, giải pháp tốt nhất cho đến nay sẽ là với 2 nút gửi.
Anurag

74

Ngoài ra còn có một cách tiếp cận khác, sử dụng thuộc tính formaction trên nút gửi:

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

Mã vẫn rõ ràng, vì nút tạo tiêu chuẩn không cần bất kỳ thay đổi nào, bạn chỉ chèn một đường dẫn định tuyến cho nút đặc biệt:

formaction:
URI của một chương trình xử lý thông tin được gửi bởi phần tử đầu vào, nếu đó là nút gửi hoặc hình ảnh. Nếu được chỉ định, nó sẽ ghi đè thuộc tính action của chủ sở hữu biểu mẫu của phần tử . Nguồn: MDN


2
điều này được hỗ trợ trên tất cả các trình duyệt w3schools.com/tags/att_button_formaction.asp w3schools.com/tags/att_input_formaction.asp
Sumit Garg

8
Tôi nhận thấy câu hỏi đã cũ, nhưng tôi khuyên độc giả rằng giải pháp ngắn gọn này đáng được xem xét tốt hơn.
Jerome

2
Tôi ước tôi đã tìm thấy câu trả lời này lần đầu tiên tôi có cùng một câu hỏi. Tôi rất vui vì tôi đã quyết định xem xét sâu hơn một chút lần này. Giải pháp tuyệt vời.
rockusbacchus

1
Tôi thực sự thích giải pháp này. Tuy nhiên, tôi phải thêm một trường ẩn với mã thông báo CSRF mặc dù tôi đã sử dụng trình trợ giúp biểu mẫu hoặc Rails sẽ không chấp nhận mã thông báo. Tôi không thể tìm thấy giải pháp thay thế tốt hơn và vẫn không chắc tại sao chính xác điều này lại xảy ra hoặc chỉ cần thêm mã thông báo một lần nữa sẽ khắc phục được sự cố.
irruputuncu

Tôi nghĩ đây là giải pháp tốt hơn vì nó tôn trọng các nguyên tắc trách nhiệm duy nhất và giữ mọi thứ rõ ràng, mỗi nút thực hiện hành động riêng của nó, giữ logic trong bộ điều khiển đơn giản.
Khalil Gharbaoui

29

Ngoài ra, bạn có thể nhận ra nút nào đã được nhấn để thay đổi tên thuộc tính của nó.

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

Nó hơi khó chịu vì bạn phải kiểm tra sự hiện diện của các phím tham số thay vì chỉ kiểm tra params[:commit]giá trị: bạn sẽ nhận được params[:a_button]hoặc params[:b_button]tùy thuộc vào phím nào được nhấn.


2
Vẫn không tách chế độ xem khỏi bộ điều khiển.
slowpoison

1
Có, nếu decouple có nghĩa là tránh một số logic trong hành động để định tuyến đến hành động cuối cùng mà bạn đúng, chúng vẫn được ghép nối. Ý tôi chỉ là nếu bạn sử dụng thuộc tính name trong logic đó thì bộ điều khiển của bạn độc lập với những gì được hiển thị trên nút. Cảm ơn, đã chỉnh sửa
masciugo

4
Cái này có vẻ tốt hơn cái được chấp nhận trong các tình huống i18n vì "giá trị" được hiển thị và nếu bạn đang hiển thị các ký tự Unicode thì nó sẽ lộn xộn.
xji

2
Tuy nhiên, các thông số không được thông qua. Tôi đang sử dụng đá quý simple_form. Có mối tương quan nào không.
xji

1
Điều này không tách rời chế độ xem khỏi bộ điều khiển, nhưng ít nhất nó cũng tách văn bản được hiển thị từ bộ điều khiển. IMO tốt hơn nhiều.
Mic Fok

13

Giải pháp tương tự cho giải pháp do @ vss123 đề xuất mà không cần sử dụng bất kỳ viên ngọc nào:

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

Lưu ý rằng tôi tránh sử dụng giá trị và thay vào đó sử dụng tên đầu vào vì giá trị của nút gửi thường được quốc tế hóa / dịch. Ngoài ra, tôi sẽ tránh sử dụng điều này quá nhiều vì nó sẽ nhanh chóng làm lộn xộn tệp tuyến đường của bạn.


9

Chúng tôi đã giải quyết bằng cách sử dụng các ràng buộc nâng cao trong đường ray.

Ý tưởng là có cùng một đường dẫn (và do đó có cùng một tuyến đường và hành động được đặt tên) nhưng với các ràng buộc định tuyến đến các hành động khác nhau.

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

CommitParamRoutinglà một lớp đơn giản có một phương thức matches?trả về true nếu tham số cam kết khớp với bản thể hiện đã cho. giá trị.

Điều này có sẵn dưới dạng một gem commit_param_matching .


3

Một câu hỏi cũ, nhưng vì tôi đã phải đối mặt với tình huống tương tự, tôi nghĩ tôi sẽ đăng giải pháp của mình. Tôi đang sử dụng hằng số bộ điều khiển để tránh tạo ra sự khác biệt giữa logic bộ điều khiển và nút xem.

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

Và sau đó trong chế độ xem:

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

Bằng cách này, văn bản chỉ tồn tại ở một nơi - như một hằng số trong bộ điều khiển. Tuy nhiên, tôi vẫn chưa cố gắng tìm ra cách thực hiện điều này.


Bạn hiểu "i18n" nghĩa là gì?
skrrgwasme

Điều này có thích hợp hơn khi sử dụng các ràng buộc trong tuyến không? Cảm ơn!
Timothy T.

@Scott: i18n có nghĩa là 'quốc tế hóa' - về cơ bản, bạn sẽ hỗ trợ nhiều ngôn ngữ như thế nào. Tôi chưa thực sự xem xét nó, vì vậy tôi không hiểu lắm về cách nó hoạt động hoặc cách triển khai nó.
Draknor

@Angela - có lẽ là không :) Và thực ra, sau khi cấu trúc lại mã của mình, tôi chỉ đơn giản tạo ra nhiều biểu mẫu, mỗi biểu mẫu có các hành động khác nhau, thay vì một biểu mẫu nguyên khối duy nhất chứa một loạt các biểu mẫu không liên quan.
Draknor

1

Tôi có một số lượng lớn các nút gửi trên biểu mẫu của mình nhờ vào nested_form_fields, vì vậy chỉ sử dụng tên là không đủ đối với tôi. Tôi đã kết thúc việc bao gồm một trường nhập ẩn trong biểu mẫu và sử dụng Javascript để điền nó khi một trong các nút gửi biểu mẫu được nhấn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.