Capybara::ElementNotFound on Dropdown Collection Select using Rspec - ruby-on-rails-3

I've been banging my head against the wall trying to figure out why this test isn't passing in Rspec. It works in the browser.
I have a Course form that belongs_to a Grade object. In the Course form, there is a select box that allows the user to select Grade:
<%= form_for [current_user, #course] do |course| %>
...
<%= course.label :grade_id, "What age are the students?" %>
<%= course.collection_select(:grade_id, Grade.all, :id, :grade_level, options ={:prompt => "Select Grade"}) %>
My test in Rspec looks like this:
describe "A workign form" do
before do
sign_in_via_form #signs the user in
visit new_user_course_path(#user) #references #user, defined in Helper
end
let(:course){#user.courses}
context "With valid information" do
it "adds a course" do
expect {
fill_in 'course_name', with:'Course Name'
select 'Fall', from: 'course_course_semester'
select '2012', from: 'course_course_year'
select 'Grade 5', from: 'course_grade_id'
fill_in 'course_summary', with: 'Perfunctory Summary'
fill_in 'course_objectives_attributes_0_objective', with: "an objective"
click_button "submit"
}.to change(course, :count).by(1)
end
end
...#other tests
end #describe block
The HTML generated in my form looks like this:
<label for="course_grade_id">What age are the students?</label>
<select id="course_grade_id" name="course[grade_id]"><option value="">Select Grade</option>
<option value="1">Kindergarten</option>
<option value="2">Grade 1</option>
<option value="3">Grade 2</option>
<option value="4">Grade 3</option>
<option value="5">Grade 4</option>
<option value="6">Grade 5</option>
<option value="7">Grade 6</option>
<option value="8">Grade 7</option>
<option value="9">Grade 8</option>
<option value="10">Grade 9</option>
<option value="11">Grade 10</option>
<option value="12">Grade 11</option>
<option value="13">Grade 12</option>
<option value="14">High School</option>
</select>
Let me know if there's other code needed; I'm more than happy to provide it. My other select boxes are working, but they're also part of the model with Arrays driving the contents. In this case, though, an associated model is driving the content. I'm not sure if that matters, there it is if it does.

The data for the dropdown comes from the database. Rails uses separate DB for test, and its tables are empty by default. So you need to populate the grades table in order to have some options in the dropdown.
With FactoryGirl it can looks like
FactoryGirl.define do
factory :grade do
sequence(:grade_level) { |n| "Grade #{n}" }
end
end
And the test
describe "A workign form" do
before do
sign_in_via_form #signs the user in
FactoryGirl.create_list(:grade, 14) # fill the grades table before visit the page
visit new_user_course_path(#user) #references #user, defined in Helper
end
...

Related

Capybara: Unable to find css for collection_select and text_field_tag

I have a collection_select and text_field_tag like this:
<%= form_tag method_path(#test.id), method: :get do %>
<%= collection_select(:test, :id, Test.all, :id, :id, prompt: true, include_blank: 'Select Test') %>
<%= text_field_tag(:input_test_questions, 'Test ids') %>
<%= submit_tag "Add" %>
<% end %>
This generates the following html:
<select name="test[id]" id="test_id"><option value="">Select Test</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
<input type="text" name="input_test_questions" id="input_test_questions" value="Test ids">
<input type="submit" name="commit" value="Add">
I am trying to write integration test using Capybara for the above. To select and input I wrote like this:
select "2", from: "#test_id"
fill_in "input_test_questions", with: "1"
But I am getting the following errors:
Capybara::ElementNotFound: Unable to find css "#test_id"
Capybara::ElementNotFound: Unable to find field "input_test_questions" that is not disabled
How can I rectify the error so that Capybara finds and selects and fills with the above options?
The from option of select is used to locate the <select> element by its name, id, test_id attribute, or label text. It does not take a CSS selector.
select "2", from: "test_id" # find by id
select "2", from: "test[id]" # find by name
fill_in "input_test_questions", with: "1" should work as written against the HTML shown, unless you have JS/CSS behavior that is hiding the text input on the page. If you are hiding it then Capybara can't fill it in because a user wouldn't be able to.
Note: It shoudln't really be possible for the error message you show Capybara::ElementNotFound: Unable to find css "#test_id" to come from the code you show, unless you're using a REALLY old version of Capybara. Hopefully that was just an incorrect copy/paste from other attempts you made.

How to properly perform a new action in rails 3 with has_many through?

OK Updating this question heavily based on progress made, also simplifying this by eliminating some info not pertinent to the problem.
I've been reviewing a lot of posts and railscasts about has_many :through but am still having an issue with a relatively simple /new form... Here is the model:
/app/models/user.rb (Think of a user as a Doctor)
has_many :intakes
has_many :patients, :through => :intakes
accepts_nested_attributes_for :intakes
/app/models/intake.rb
belongs_to :user
belongs_to :patient
/app/models/patient.rb
has_many :intakes
has_many :users, :through => :intakes
accepts_nested_attributes_for :intakes
accepts_nested_attributes_for :users
Now, what I want to do is a simple /patients/new and have a form come up with some patient information and two drop-downs for Doctors (users). The classical way to do this has been explained as:
/app/controllers/patients_controller.rb
def new
#patient = Patient.new
2.times { #patient.intakes.build.build_user }
end
and in my view:
/app/views/patient/new.html.erb
<%= form_for #patient do |f| %>
<%= render 'fields', :f => f %>
<%= f.submit "Add Patient" %>
<% end %>
And, finally, the fields partial:
/app/views/patients/_fields.html.erb
<%= f.fields_for :intakes do |builder| %>
<%= builder.label :first_name, "Cared for by" %>
<%= select("patient[new_intake_attributes]", "user_id",
User.justthishosp(current_user.hospital).collect {
|user|
[ user.first_name+" "+user.last_name, user.id]} ) %>
<% end %>
Now the above actually does cause the form to come up, and there are two "intake" html select elements! Yea! The problems are A) Only the first intake saves because B) The intake HTML format doesn't match what I see in all of the recommendations and C) I cannot determine the proper SELECT syntax to get the HTML format to match the recommendations.
The HTML that the above code produces is:
<label for="patient_intakes_attributes_0_first_name">Cared for by</label>
<select id="patient_new_intake_attributes_user_id"
name="patient[new_intake_attributes][user_id]">
<option value="1"> </option>
<option value="4">Dan Akroyd</option>
<option value="2">Dave Collins</option></select>
</p>
<p>
<label for="patient_intakes_attributes_1_first_name">Cared for by</label>
<select id="patient_new_intake_attributes_user_id"
name="patient[new_intake_attributes][user_id]"><option value="1"> </option>
<option value="4">Dan Akroyd</option>
<option value="2">Dave Collins</option></select>
Note, specifically the form of the select name:
name="patient[new_intake_attributes][user_id]"
What they want in Advanced Rails Recipes is:
name="patient[new_intake_attributes][][user_id]"
And they way they say you should achieve that is with this select line:
select("patient[new_intake_attributes][]", "user_id",
However, that syntax gives me
*`#patient[new_intake_attributes]' is not allowed as an instance variable name*
I have tried so many variations of [] and patient, Patient, :patient and I cannot get anything to give me HTML that contains the empty [] after patient[new_intake_attributes]
So, at this point I've got TWO select boxes on the form, but only one saves because only one is being passed in the params hash. Which, BTW looks like this:
(PatientsController.create) params[:patient]:
{"first_name"=>"Nine", "last_name"=>"Niner", ...,
"new_intake_attributes"=>{"user_id"=>"2"}, "pri_loc_id"=>"6"}
and I need:
"new_intake_attributes"=>[{"user_id"=>"2"},{"user_id"=>"4"}]
Or any kind of collection which I could gladly process in my virtual method.
Whew! Holy Smokes!
Thanks!

Rails way to implement a simple dropdown

I have a simple dropdown that I want to populate from a model. I don't want to bind it to another model at all, just a simple standalone form with a list of items and handle storing the state of the dropdown in a session variable, I can achieve it with a more brute force approach as shown but it doesn't feel very 'rails' to me.
<form action='/home/switch' method='post'>
<select name="all_items">
<% #items.each do |i| %>
<option value="<%= i.id %>" <%= i.id.to_s == session[:current_item] ? "selected" : "" %>><%= i.name %></option>
<% end %>
</select>
<input type="submit">
</form>
Is there a better way to do this in Rails?
Update: Yep. collection_select worked for me:
<%= collection_select(:item, :id, Item.all, :id, :name, {:selected => session[:current_item].id}) %>
Take a look at form_tag, select_tag, options_from_collection_for_select, and/or collection_select.
So your example might look like this (not tested, may have typos)
<%= form_tag('/home/switch') do %>
<%= select_tag('all_items', options_from_collection_for_select(#items, 'id', 'name')) %>
<%= submit_tag %>
<%= end %>
This is missing the "selected" bit, take a look at the docs for that.

Rails Trying to submit a form onchange of dropdown

I have my Ajax working, builtin Rails javascript, with the submit button. However, I would like it to submit when I change the value of the dropdown box and eliminate the button. In my research I found what looks like the correct solution but I get no request to the server. Here is my dropdown form code, note it still has the submit button that worked before I added :onchange:
<% form_tag('switch_car', :method => :put, :remote => true) do %>
<div class="field">
<label>Car Name:</label>
<%= select_tag(:id, options_from_collection_for_select(active_cars, "id", "name"),
:onchange => ("$('switch_car').submit()"))%><%= submit_tag "Switch Car" %>
</div>
<% end %>
Here is the HTML generated:
<form accept-charset="UTF-8" action="switch_car" data-remote="true" method="post">
<div style="margin:0;padding:0;display:inline">
<input name="utf8" type="hidden" value="✓" />
<input name="_method" type="hidden" value="put" />
<input name="authenticity_token" type="hidden" value="PEbdqAoiik37lcoP4+v+dakpYxdpMkSm7Ub8eZpdF9I=" />
</div>
<div class="field">
<label>Car Name:</label>
<select id="id" name="id" onchange="$('switch_car').submit()">
<option value="9">Truck</option>
<option value="10">Car</option>
</select>
<input name="commit" type="submit" value="Switch Car" />
</div>
Thanks in advance for any help.
Replace your onchange with this,
onchange: "this.form.submit();"
this.form.submit() will not work if form is remote: true and rails-ujs is in use. In that case, a regular submit will occur instead of XHR.
Instead you should:
onchange: 'Rails.fire(this.form, "submit")'
You can read here for more details.
This is what I was able to do to get it to work. I named the form switch_car by using :name => "switch_car" and used the following javascript.
:onchange => ("javascript: document.switch_car.submit();")
I am still looking for a better answer so I will updated if I find something. This doesn't use submit .js for some reason. It processes it as HTML unlike the submit button which uses AJAX to update only the changing page elements. But this is the best I have been able to find so far.
Depending on the js library you are using:
Prototype: :onchange => ("$('switch_car').submit()")
Jquery: :onchange => ("$('#switch_car').submit()")
If you are using the defaults and your rails version is below 3.1, then prototype is the default library.
This is an old question, but none of the above answers work for me. They all result in a text/html request.
The following works, e.g. (the hide class sets css display: none):
<%= form.radio_button :tier_id, tier.id, onchange: "$('#submit-button-id').click();" %>
together with:
<%= form.submit "Save changes", id: 'submit-button-id', class: 'hide' %>
A more general solution using jQuery (I don't need to know the name of the form) is:
onchange: "$(this).parent('form').submit();"
This seems to have been around for a while but, I'll post my findings anyway since I haven't found this explanation anywhere yet.
I came across this article which describes quite well what's the problem when triggering a ajax request via the submit() method (with or without jQuery or Handler). The author then recommends to form your own AJAX request. That is not required and shouldn't be done to make use of the logic within rails.js (jquery-jus gem).
Problems with triggering submit() manually occur since rails.js binds and listens to an event that is namespaced submit.rails. To manually trigger a submission use
onchange: 'javascript: $( this ).trigger("submit.rails")'
on the element or the form.
For a select_tag, just add:
{:onchange => "myHandler();" }
where your handler will be:
this.form.submit();
Also, if onchange doesn't work you might want to try onChage with a capital C.
Finally, make sure NOT TO CONFUSE a select_tag with a form select.
See my answer to a similar question, only regarding a form select
Adding An Onchange Event To A Form Select
Time at 2021, with Rails 6
make a hidden submit then use js click() function:
<%= form_with(modle: #user, local: false) do |f| %>
<%= f.select :menu1, ["option1","option2"], {}, onchange: "javascript:this.form.commit.click();" %>
<%= f.submit 'save', class: "hidden" %>
<% end>
reference: https://stackoverflow.com/a/8690633/15461540
If you want to learn rails way ajax submit on fields change here is the code.
<%= select_tag(:id, options_from_collection_for_select(active_cars, "id", "name"),
data: { remote: true, url: your_ajax_route_path }%><%= submit_tag "Switch Car" %>
data: { remote: true, url: your_ajax_route_path }
will automatically submit your input to your_ajax_route_path. If you are using a form builder then you should use with input_html
input_html: { data: { remote: true, url: your_ajax_route_path } }
like this. I hope it'll be useful for you
None of the solutions was working for me so I used the given below solution.
$("#q_dimension_id_eq").on("change", function (e) {
$(this).closest("form").submit();
});
I'm using rails 4.2.1 with jquery_ujs and it works for me:
onchange: 'jQuery(this).parent().trigger("submit")'
OBS.: It assumes the element is immediately child from form. You must adjust parent() according your DOM tree.

How do I customize the menu option in options_from_collection_for_select in Rails 3?

I have this in my view:
<%
#plan = Plan.limit(4).all
plan ||= Plan.find(params[:plan_id])
%>
<%= select_tag "Plan", options_from_collection_for_select(#plan, 'id', 'name', plan.id) %><br />
That produces the following:
<select id="Plan" name="Plan"><option value="1">Gecko</option>
<option value="2" selected="selected">Iguana</option>
</select>
However, I would like it to produce the following options:
<select id="Plan" name="Plan"><option value="1">Gecko ($50)</option>
<option value="2" selected="selected">Iguana ($99)</option>
</select>
Where the price in brackets is plan.amount.
You could create a method in your model which returns the value you want to present:
class Plan < ActiveRecord::Base
...
def display_name
"#{self.name} (#{self.amount})"
end
end
# View
<%= select_tag "Plan", options_from_collection_for_select(#plan, 'id', 'display_name', plan.id) %>
options_from_collection_for_select also accepts the text method as lambda so you can write the custom method in the view instead of model incase you have some view specific code that you don't want to pollute the model with.
<%= select_tag "Plan", options_from_collection_for_select(#plan, 'id', lambda { |plan| "#{plan.name} (#{plan.amount})")}, plan.id) %>