Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fallback to select if array of checkboxes fail #34

Merged
merged 1 commit into from
Sep 19, 2014
Merged

Conversation

seanpdoyle
Copy link
Contributor

Allows fields that are arrays of strings to be passed to <select multiple>
inputs.

@@ -3,6 +3,8 @@ module Inputs
class ArrayInput < Input
def fill
value.each { |checkbox| check checkbox }
rescue
value.each { |option| select option, from: label }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@calebthompson this is obviously a lazy and naive implementation. I was hoping you'd be able to point me to a more elegant approach if one exists.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha, a little maybe. Check out StringInput for how I've done this before.

private

def has_select?
page.has_select?(label)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the docs, it doesn't look like we can filter for <select multiple="true">

Would we really need to check for this? Wouldn't a select's single/multiple selection come out when trying to fill it in and assert on the side effects of submitting the form?

Also, wouldn't the onus be on the caller to pass in the correct label?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They might, but if we only check for the select, we just change the
selection for each array element then submit - no errors.

I'm a big fan of the Unix philosophy of failing early and loudly.

On Mon, Sep 15, 2014 at 02:26:37PM -0700, Sean Doyle wrote:

@@ -2,6 +2,26 @@ module Formulaic
module Inputs
class ArrayInput < Input
def fill

  •    if has_select?
    
  •      select_options
    
  •    else
    
  •      check_boxes
    
  •    end
    
  •  rescue Capybara::ElementNotFound
    
  •    raise InputNotFound.new(%[Unable to find input "#{label}".])
    
  •  end
    
  •  private
    
  •  def has_select?
    
  •    page.has_select?(label)
    

Looking at the docs, it doesn't look like we can filter for multiple selects.

Would we really need to check for this? Wouldn't a select's single/multiple selection come out when trying to fill it in and assert on the side effects of submitting the form?

Wouldn't the onus be on the caller to pass in the correct label?


Reply to this email directly or view it on GitHub:
https://github.com/thoughtbot/formulaic/pull/34/files#r17569921

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

has_selector? should take attribute selectors: has_selector? "select[multiple]"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When trying to call has_selector?("select[multiple]", label: label), the failure reads

invalid keys :label, should be one of :count, :minimum, :maximum, :between, :text, :visible, :exact, :match, :wait

I don't think any of those accepted keys apply to an input's label

I'm not sure how to find the select with both multiple and the corresponding label

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, if the select isn't multiple, we'd just select the last option provided.

Is correcting this a formulaic concern? Is it a form-filling 'failure'?

I don't think 'silently' failing will be an issue, since controllers expecting an array will be requiring form[field][] while controllers expecting a single option will require form[field].

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally speaking, it's a test's job to show mistakes. The more verbose we can be about that, the more useful Formulaic is.

Consider:

Formulaic::InputNotFound No select or checkbox has all options in [x, y, z].

versus:

ActionController::UnpermittedParameters: found unpermitted parameters: letters

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, the former is much more helpful.

However, I don't know how to move forward with this

@calebhearth
Copy link
Owner

Pushed up ugly but working code. It could benefit from some extract method.

@calebhearth
Copy link
Owner

Your failing test is in a branch at sd-select-array-failing

@seanpdoyle
Copy link
Contributor Author

Nice work, I'll take a look tomorrow

end
end

class SelectInput < ArrayInput
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@calebthompson I know that private classes are more or less a no-no, but I wanted to get your feedback on the extraction before I went any further.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with them.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might make more sense to have them just be PORO helper classes though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to do that, we'd have to expose label, value and somehow share contains_all_options?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

label & value can still be passed in. contains_all_options? could be moved down into those, but then it'd be duplicated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right, I forgot we're passing in label and value.

My first instinct was to use SimpleDelegator, and I passed in self instead of label, value. I got to the point where I made those fields public, but then had to duplicate contains_all_options?, so I fell back to inheritance.

@seanpdoyle
Copy link
Contributor Author

Right, I plan on squashing and authoring a good commit message before this gets merged.

@seanpdoyle seanpdoyle force-pushed the sd-select-array branch 3 times, most recently from 5d91b18 to 7b3d1cb Compare September 19, 2014 18:23
@seanpdoyle
Copy link
Contributor Author

@calebthompson ok squashed my commit and split out the files.

What else is blocking this?

end
end
end
end

require 'formulaic/inputs/checkbox_input'
require 'formulaic/inputs/select_input'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These need to be at the bottom of the file, since they both depend on ArrayInput

@@ -26,6 +26,8 @@ def load_translations
awesome: Are you awesome?
bio: Biography
date_of_birth: Date of birth
likes: Likes
dislikes: Dislikes
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have / had a passing interest in not having these just be humanized versions of the translations, but that doesn't really matter anymore since we have a lot of those.

@calebhearth
Copy link
Owner

LGTM.

@seanpdoyle
Copy link
Contributor Author

Should these commits get squashed to 1 or are you ok with them as-is?

@calebhearth
Copy link
Owner

Not much of a story being told, I think. Go ahead and squash them.

@seanpdoyle seanpdoyle deleted the sd-select-array branch September 19, 2014 21:20
* Allows fields that are arrays of strings to be passed to `<select multiple>`
inputs
* Update README.md
* Add coverage for Array of checkboxes
* Rescue `Capybara` errors and rethrow as Formulaic
* Check for presence of all options in ArrayInput
* Raise Formulaic::InputNotFound with useful message if not all options
  are present in either a select[multiple]'s options or as checkboxes.
* Ensure checkboxes exist with `:has` http://dev.w3.org/csswg/selectors4/#relational
* Extract `SelectInput` and `CheckboxInput`
 * Both are subclasses of `ArrayInput`. Now, `ArrayInput#fill` chains together
   successive calls to `SelectInput#fill` and `CheckboxInput#fill`, finally
   failing with an informative exception if neither inputs exist on the page.
* Enure that I18n's aren't humanized
calebhearth added a commit that referenced this pull request Sep 26, 2014
Formulaic now knows how to `select` from a `select[multiple]` if it
can't `check` array options as `input[type=checkbox]`.

It will also refuse to fill an `Array` value if all elements can't be
selected or checked (and they must all be the same action).

#34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants