Empty array value being input with simple_form ent

2019-07-26 01:00发布

I'm still new to rails and simple_form and have been trying to implement a multiple select option to give a user multiple roles.

Current input looks like this

<%= f.input :secondary_role, :collection => UseridRole::VALUES, :include_blank => false,:label => "Secondary Role(s):", :input_html => {  :class => " simple_form_bgcolour simple_form_position overide_selection_field_width", :size => 4, multiple: true } %>

So, this does work, but is including an empty value at the start of my array:

"secondary_role" : [
        "",
        "admin"
    ]

I have the same code above which works for my primary_role value which is a string, but my secondary_role can have multiple values so is stored as an array.

Where should I be looking to fix this issue?

2条回答
对你真心纯属浪费
2楼-- · 2019-07-26 01:29

It seems like Rails is adding a hidden field to the collection. Try adding include_hidden: false to your form input.

查看更多
Fickle 薄情
3楼-- · 2019-07-26 01:49

There are several options to get away with empty values for multi-selects.

As with most things in web dev, there's a million ways to skin this cat.

Option 1: JS Catch & Remove

If you choose, you can catch the form in JS, remove the empty strings then call form.submit -- In this case for you, there's no real benefit over the other options

Option 2: Strong Params Controller catch

You can use reject the empty ones in your params methods

def object_params
  obj_p = params.require(:user).permit(:primary_role, secondary_role: [] )
  obj_p[:secondary_role].reject! { |role| role if role == ""}
  up
end

Option 3: Reject blanks in the model

#app/models/object_model.rb
before_save :remove_blanks

private 
def remove_blanks
  self.secondary_role.reject!(&:blank?).to_s
end

If the option might ever be updated outside of your controller, then the DRYer way is in the model.


Edit

You can't remove all the blanks if you're trying to catch elements of an array that have been removed, it will work if there is still an item in the array, at least one, but if you remove all the elements, it won't pass the form element to the controller at all.

Instead use the form to dictate to the user to set to nil & use the model method above:

<%= f.input :secondary_role, :collection => UseridRole::VALUES, :include_blank => "Remove All Secondary Role(s)", :label => "Secondary Role(s):", :input_html => {  :class => " simple_form_bgcolour simple_form_position overide_selection_field_width", :size => 4, multiple: true } %>

In addition, if that option is selected, I would probably use javascript to unselect everything else, just so that it's obvious to the user what is about to happen.

Something like this js snippet

var el = document.querySelector("#user_secondary_role")
el.addEventListener('change', function() {
  if (el.value == "") {
    roles = el.querySelectorAll("option")
    for (var value of roles) {
      (value.value == "") ? value.selected = true : value.selected = false
    }
  }
});

Then in your model use the remove_blanks method on a before_save call last listed in option 3.

Breakdown. Here's what's happening.

  1. In your form element, go ahead and include_blank - this will ensure that "" is passed if the element is empty. Next, make sure that the include_blank has a title, the value of which will always be "", but you need to give the user something to click on that makes sense.
  2. Add some javascript so when a user DOES click on "Remove All Secondary Roles" - the form in front them changes and deselects the other options.
  3. The model method is going to remove blanks, plain and simple, but this will not work unless you're allowing the blanks to be passed in, otherwise your element will be empty and never reach your controller/model. You can verify that by watching your development.log and checking out what params are passed in the POST.
查看更多
登录 后发表回答