Select from last matching select menu in Capybara 1.1.2 - capybara

I'm working with a Hobo app using the input_many tag to handle a many-to-many relationship on a form. This puts + and - buttons on the page, and the + adds a new select tag for picking the model on the other side of the relationship. This means that there can be an arbitrary number of select menus with very similar characteristics, distinguished only by an array index, like this:
<select class="input belongs_to data_set_graph" name="graph_pane[data_set_graphs][0][data_set_id]">
[...options...]
</select>
<select class="input belongs_to data_set_graph" name="graph_pane[data_set_graphs][1][data_set_id]">
[...options...]
</select>
N.B. the join of GraphPanes and DataSets is polymorphic (there are many kinds of GraphPanes) so the actual CSS class name varies according to the kind of pane - it could be data_set_a_graph_pane_data_set or data_set_b_graph_pane_data_set.
We've been using Capybara 1.1.2 to test this. As long as we're only associating one DataSet with a GraphPane, we've been able to select them with a step definition like this:
included_defs.each do |data_set_name|
click_button "+"
select_node = find(:css, '.input-many-item select') # There may be more than one of these?
select_node.find(:xpath, XPath::HTML.option(data_set_name), :message => "cannot select option with text '#{data_set_name}'").select_option
end
However, now we need to associate two DataSets with a GraphPane, and the find(:css, '.input-many-item select') fails because there are two matching nodes.
It seems to me that if I could just always pick the last one, this would work, but I can't figure out how to do this with Capybara's selectors. (I think part of the problem is that it's not clear to me, in most of the examples I find, whether they refer to the 1.x DSL or the 2.x series.)
Ideas for sorting this out elegantly are welcome.

The answer turns out to be using the "all" finder in Capybara:
included_defs.each do |data_set_name|
click_button "+"
select_node = all(:css, '.input-many-item select').last # There may be more than one of these
select_node.find(:xpath, XPath::HTML.option(data_set_name), :message => "cannot select option with text '#{data_set_name}'").select_option
end
all is like find, but it returns an array of matching nodes, so I can use .last and always get the last one.

Related

Instantiating Subclasses from dropdown option

I have a page that allows a user to run a report. I'm using Rails 5. My reporting page allows the user to select different report types. So, the user has a drop down with the following options: Tax, Order, Refund, and so on.
Depending on their selection, I will instantiate a subclass of my Reports::Report class for their selected option.
Currently, I am doing this:
if params[:report_type] == "Tax"
Reports::Tax.new.run
elsif params[:report_type] == "Order"
Reports::Order.new.run
elsif params[:report_type] == "Refund"
Reports::Refund.new.run
end
How can I restructure this code so that I don't have an endlessly long list of conditionals for running certain report types? What's the more OOP approach to solving this?
Thanks in advance.
Well, if your options values map to the exact classes you have defined in your Reports module, (I mean for example, your select options are Tax, Order, Refund, and you have exact Reports::Tax, Reports::Order, Reports::Refund defined) you can try the following
begin
report = Object.const_get("Reports::#{params[:report_type]}")
report.new.run
rescue
# error handler for not existing report type
end

How to get value in controller of an bootstrap-multiselect-rails

I'm new to rails and web. I use the 'bootstrap-multiselect-rails' gem to create a select box and normal inputs.
When I click the submit button, I don't retrieve the select box informations in the params variable (the inputs are well retrieve).
This is probably due to the bootstrap-multiselect gem that overrides the behavior of the select box by replacing it with a ul,li system.
%select#select-type{:multiple => "multiple"}
- #list_of_type.each do |type|
%option{value: "#{type.label}"} #{type.label.upcase_first}
I have seen answers that explains in retrieving the information in javascript but how to perform treatments on its information in the controller?
In your select field I cannot see that you assigned a param to it. Usually select goes like this: <%= select :input, etc... where :input is the param you want to save into your model.
Rails docs give following example:
select("post", "person_id", Person.all.collect {|p| [ p.name, p.id ] }, { include_blank: true })
So the problem is that you did not specify the param. It is also not empty, it is not mentioned at all in your Parameters. Correct?! Than please check the basic docs again on how to create a select field and add the param as requested. Unfortunately, I do not know the exact syntax using your gem.
I am also not sure about the :multiples=>"multiple". or should it be multiple: true? But I think your version might work with the gem. However, your haml only creates the HTML select with #id and multiple: true. But what you want is something like this
<select name="post[category]" id="post_category">
So that the param is clear in the select.
Afterwards, when you have saved the param you can use it also in your controller action.
In conclusion: Add the param to your select field. I don't know how to do this with the gem but you might find some docs may be, or check basic rails docs which might help you out here for sure. Also SO has many questions on select with rails. Good luck!
Can you show the rails code for the multi form? You just need to add a value to each select option which will be stored by rails if you have permitted the params in controller and set up a column for it migrations.
If questions on how to add value to select_tag check out the rails docs. In your html markup i cannot see if the options have value.

Select tag & options for select 101

Can someone explain me how this exactly works ?
Problem:
I have a Scaffold and run the migration:
rails g migration AddRarityToTags rarity:string
For the rarity input i need a dropdown displaying a list of options to select from.
e.g. Rarity = Free
Common
Rare
Epic
If i'm right i need something like this:
select_tag :rarity, options_for_select(#rarity)
I searched a lot but it didn't helped much, i got more confused.
Can someone help me out ?
Imagine putting the raw options into the tag as a string:
select_tag :rarity, '<option>Free</option><option>Common</option>...'
That's what options_for_select returns, if you pass in an array:
select_tag :rarity, options_for_select(['Free', 'Common', ...])
See: http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-options_for_select
To enforce the "dumb views" rule, and to let others use that array, you can move it to the model:
class Tag < ActiveRecord::Base
RARITY_LEVELS = %w(Free Common Rare Epic)
end
...
select_tag :rarity, options_for_select(Tag::RARITY_LEVELS)
Both me and the OP would like to know if Rails, or any gems, let us get any DRYer than this; if, for example, Rails lets us attach the RARITY_LEVELS directly to the rarity field...

Capybara won't select item from select

I'm using Capybara to test a little Web app I'm writing. It refuses to select the right item from a select. Here's the code:
before do
fill_in 'Assignment', with: "blah blah blah"
select student.name, from: "assignment[student_id]"
end
I've tried every supported format in the "from" field. I've used the id, the name, and the label text to try and select the correct element. I've even booted the rails server in test, and manually ran through the steps in my test in the console. No matter what I do, capybara kicks back:
cannot select option, no option with text 'John Doe' in select box 'assignment[student_id]'
As stated before, I have kicked up the rails server in the test environment, and then manually added users to the database the same way I have done in my tests. I am 100% confident of the fact that there is indeed an option with text 'John Doe' in select box 'assignment[student].' This leads me to believe that I must be using the select method incorrectly. Can someone enlighten me?
Does the select from: need the select fields name or the ID?
Try it with the ID instead (assuming standard form style):
select student.name, from: "assignment_student_id"
If you inspect source on the select element you can confirm the fields ID.
Does it use the value of the option element rather than the text? Again, inspect and see what the value of "John Doe" is and see if it works by using student.id.
select student.id, from: "assignment[student_id]"
Lastly, have you tried the syntax in the documentation that includes the page?
page.select student.name, :from => 'assignment[student_id]'
The problem wasn't with the select code. I forgot how FactoryGirl's let works. I called build through a relationship on a User created by Factory Girl, and then tried assigning that result to student via let. Unfortunately, since let is lazy, it wasn't being created when it needed to be, so basically the page was getting called up before the student object was even created. I moved the code in my let statement into a before, and then assigned student using let and User.students.first.

Extra, unwanted field from haml block rails partial

I'm outputting a collection in haml
#- if #fields.count>0
.sfields
#= render :partial=>"sfields/field", :collection=>#fields, :as=>:field
= render #fields
When there are zero fields, there is always one phantom field rendered. When I add 'if #fields.count>0' then when there is zero there is no output, but as soon as I add one field I get two rendered, the one I added and a phantom field.
This is the first I've run into this and I'm not sure what I did that is outputting a phantom field. I remember seeing something similar, but can't remember where I saw it, and my search turned up nothing relevant atm.
EDIT 1:
Contents of partial
.sfield
= field.name
.fielditems
#- fields.items each do |i|
#= render :partial=>"items/item", :locals=>{:i => i}
= render field.items
So, there is always an extra sfield hanging around.
EDIT 2
Abstractly, I have this:
Show action -> partial for fields -> partial for field items -> partial for field item choices, 4 different places pulled into one page.
So fields is a collection of items and an item is a collection of choices. Even after going through and making the renders more rails default (e.g. render #fields, render field.items, etc.) I still have that phantom field. I don't want to hide it with js or something (ack awful), so I need to figure some solution which entails more trial and error and reading.
It works, but is ugly with the phantom field hanging on.
EDIT 3
I've taken several steps back combined everything into one template, sans partials. Still there. Something basic I'm doing wrong or missing is adding this phantom field, so annoying. It isn't necessarily the partials then.
EDIT 4: SOLVED
refined the #fields select in the controller to select only fields attached to the item I'm showing
e.g.
#fields = #showing.fields
to
#fields = #showing.fields(:showing_id=>#showing.id)
I'd still like to know why it was doing that grr...
Your #fields wouldn't be a list of hashes would it?
NOTE: Due to backwards compatibility concerns, the collection can’t be one of hashes. Normally you’d also just keep domain objects, like Active Records, in there.
-- http://api.rubyonrails.org/classes/ActionView/Partials.html
Note EDIT 4: SOLVED
refined the #fields select in the controller to select only fields attached to the item I'm showing
e.g.
#fields = #showing.fields
to
#fields = #showing.fields(:showing_id=>#showing.id)

Resources