How to add additional params to a button_to form?

2020-02-16 08:11发布

I want to have a Submit button. It updates one field on the submission; submission.state = :submitted

Now, I could make a custom route and a custom action and just post to that. But that seems really heavy-handed. Especially since I'll also have a reject button and possibly more. Needing a custom route & action for each of those seems downright silly to me.

It would be much nicer if I could do something like

button_to "Submit", submission_url(submission), :method => :put, :submission => { :state => :submitted }

Which would post to the submission's update method and update only the desired field.

But that doesn't work. How can I make it work? Or do you have a better idea of how to do this?

7条回答
我命由我不由天
2楼-- · 2020-02-16 08:18

Add params:{} at the end, it will generate hidden_field

<%= button_to user.name, user, class:"btn btn-default", style:"", method: :patch, remote: true, params: { a_field: false, an_other_field:"a new value" } %>
查看更多
看我几分像从前
3楼-- · 2020-02-16 08:20

So, as from this rails pull request : https://github.com/rails/rails/pull/10471

Here is what you can do to have your custom button_to.

In application_helper.rb, add these lines:

module ApplicationHelper
  // Unfortunately these 2 methods need to be redefined. I don't know how I could access the original ones.
  def token_tag(token=nil)
    if token != false && protect_against_forgery?
      token ||= form_authenticity_token
      tag(:input, type: "hidden", name: request_forgery_protection_token.to_s, value: token)
    else
      ''
    end
  end

  def method_tag(method)
    tag('input', type: 'hidden', name: '_method', value: method.to_s)
  end

  def button_to_with_params(name = nil, options = nil, html_options = nil, &block)
    html_options, options = options, name if block_given?
    options      ||= {}
    html_options ||= {}

    html_options = html_options.stringify_keys
    convert_boolean_attributes!(html_options, %w(disabled))

    url    = options.is_a?(String) ? options : url_for(options)
    remote = html_options.delete('remote')
    params = html_options.delete('params') { Hash.new }

    method     = html_options.delete('method').to_s
    method_tag = %w{patch put delete}.include?(method) ? method_tag(method) : ''.html_safe

    form_method  = method == 'get' ? 'get' : 'post'
    form_options = html_options.delete('form') || {}
    form_options[:class] ||= html_options.delete('form_class') || 'button_to'
    form_options.merge!(method: form_method, action: url)
    form_options.merge!("data-remote" => "true") if remote

    request_token_tag = form_method == 'post' ? token_tag : ''

    html_options = convert_options_to_data_attributes(options, html_options)
    html_options['type'] = 'submit'

    button = if block_given?
      content_tag('button', html_options, &block)
    else
      html_options['value'] = name || url
      tag('input', html_options)
    end

    inner_tags = method_tag.safe_concat(button).safe_concat(request_token_tag)
    params.each do |name, value|
      inner_tags.safe_concat tag(:input, type: "hidden", name: name, value: value.to_param)
    end
    content_tag('form', content_tag('div', inner_tags), form_options)
  end
end

And to use it:

= button_to_with_params 'Awesome button', awesome_action_path, method: :put, :params => {:my_param => 'my_value'}

Enjoy! Have fun Railing!

查看更多
Anthone
4楼-- · 2020-02-16 08:22

If I read things correctly what you are effectively wanting to do something specific when a standard rails form is submitted in the standard way.

Notice that when a form is submitted using e.g.

f.submit "Save Changes"

then

params[:commit] = "Save Changes"

The GOOD thing about this is that it can allow you to do some appropriate branching in the controllers update action.

The BAD thing is that it's brittle. If one day you or someone else decides to change the button text, things break.. which is bad.

K

查看更多
够拽才男人
5楼-- · 2020-02-16 08:25

The pull request mentioned by @AugustinRiedinger has been merged and is now available as of Rails 4.1.0. Now just add the params option:

params: { state: :submitted }
查看更多
趁早两清
6楼-- · 2020-02-16 08:36

I have something similar that works:

button_to "Submit", submission_url(submission, :submission => { :state => :submitted }), :method => :put

查看更多
一夜七次
7楼-- · 2020-02-16 08:39

It's not as concise, but without extending Rails, this will get me by:

= form_for submission, :html => { :class => "button_to" } do |f|
    = f.hidden_field :state, :value => :submitted
    = f.submit "Submit", :class => "link"
查看更多
登录 后发表回答