Searching within HTML elements in RSpec view tests - ruby-on-rails-4

As part of my view specs, I sometimes like to check that the right text is also rendered for a certain element on the page.
Let's say the rendered HTML is -
<div class="user-msg">
<b>Thank You!</b>
</div>
I might test in my view specs as -
expect(rendered).to match(/Thank You/)
However this could incorrectly fail or pass depending on whether there's something else on the page that also says "Thank You".
How do I search within the specific <div> in question? If this were a feature test I'd use Capybara to select the node -
within(".user-mssg") { expect(page.body).to have_content("Thank You") }
How do I find a specific HTML element (e.g. .user-msg) and search within it in my View specs?
Thanks!
Edit: "Thank you!"

rspec-html-matchers does just that:
<h1>Simple Form</h1>
<form action="/users" method="post">
<p>
<input type="email" name="user[email]" />
</p>
<p>
<input type="submit" id="special_submit" />
</p>
</form>
spec:
expect(rendered).to have_tag('form', :with => { :action => '/users', :method => 'post' }) do
with_tag "input", :with => { :name => "user[email]", :type => 'email' }
with_tag "input#special_submit", :count => 1
without_tag "h1", :text => 'unneeded tag'
without_tag "p", :text => /content/i
end

Related

Redmine Plugin Development edit form_for

I am currently developing a redmine Plugin,
so far it went well. But since I integrated the plugin into a project i cant use form_for to create an edit view.
Edit View:
Formular
<div class="box tabular">
<div class="splitcontent">
<div class="splitcontentleft">
<%= form_for (#customer) do |f| %>
<div class="splitcontent">
<div class="splitcontentleft field_name">Name </div>
<div class="splitcontentright"><%= f.text_field :name, :size => 20, required: true %></div>
</div>
</div>
<hr />
<%= render :partial => '/inventory_customers/form_custom_fields' %>
<div></div>
</div>
<div><%= f.submit submit_text %></div>
<% end %>
Controller
before_filter :find_project
...
def edit
#customer = InventoryCustomer.find(params[:id])
end
...
private
def find_project
# #project variable must be set before calling the authorize filter
#project = Project.find(params[:project_id])
end
def customer_params
params.require(:inventory_customer).permit(:name, :sap_id, :sap_name, :address, :partner, :partner_text, :active)
end
Error Message
Started GET "/redmine/projects/inventory development/prototyp/inventory_customers/3/edit" for 172.20.1.197 at 2016-08-03 16:07:45 +0200
Processing by InventoryCustomersController#edit as HTML
Parameters: {"project_id"=>"inventory-development", "id"=>"3"}
Current user: COAH (id=38)
Rendered plugins/prototyp/app/views/_inventory_menu.html.erb (0.7ms)
Rendered plugins/prototyp/app/views/inventory_customers/_form.html.erb (1.6ms)
Rendered plugins/prototyp/app/views/inventory_customers/edit.html.erb within layouts/base (2.9ms)
Completed 500 Internal Server Error in 7ms (ActiveRecord: 0.3ms)
ActionView::Template::Error (No route matches {:action=>"show", :controller=>"inventory_customers", :id=>nil, :project_id=>#<InventoryCustomer id: 3, name: "blub", partner: false, sap_name: "asdasd", address: "sadasd", active: true, sap_id: "">} missing required keys: [:id]):
2: <div class="box tabular">
3: <div class="splitcontent">
4: <div class="splitcontentleft">
5: <%= form_for (#customer) do |f| %>
6: <div class="splitcontent">
7: <div class="splitcontentleft field_name">Name </div>
8: <div class="splitcontentright"><%= f.text_field :name, :size => 20, required: true %></div>
lib/redmine/sudo_mode.rb:63:in `sudo_mode'
If i remove the form_for i can load the edit view but then i dont see a way to edit the object.
Since i just started with rails and redmine i have absolutly no idea how to fix the error or how i can do a work arround.
Use form_tag(path, :method=> 'put', :multipart => true ) do instead of form_for
path is something like customer_path.
Make sure to use another path for editing (singular) than for creating (plural, no id needed)

Overriding spree views using deface

I am trying to override some view using Deface but I got this error and warning in the console:
Deface: 1 overrides found for 'spree/shared/_header'
Deface: 'header_background' matched 1 times with 'div#spree-header'
Deface: [WARNING] No :original defined for 'header_background', you should change its definition to include:
:original => '870f2cc85da3717b7c721a3e99245cf65b607a19'
Deface: [WARNING] Circular sequence dependency includes override named: 'auth_shared_login_bar' on 'spree/shared/_nav_bar'.
Deface: 2 overrides found for 'spree/shared/_nav_bar'
Deface: 'main_menu' matched 1 times with 'nav#top-nav-bar'
Deface: [WARNING] No :original defined for 'main_menu', you should change its definition to include:
:original => 'a35cdc6247d04a90fc0aefc58f068ae2b3923eab'
Deface: 'auth_shared_login_bar' matched 1 times with 'li#search-bar'
Deface: [ERROR] The original source for 'auth_shared_login_bar' has changed, this override should be reviewed to ensure it's still valid.
Deface: [WARNING] Circular sequence dependency includes override named: 'auth_shared_login_bar' on 'spree/shared/_nav_bar'.
Deface: [WARNING] Circular sequence dependency includes override named: 'auth_shared_login_bar' on 'spree/shared/_nav_bar'.
Deface: 1 overrides found for 'spree/shared/_main_nav_bar'
Deface: 'home-link' matched 1 times with 'li#home-link'
Deface: [WARNING] No :original defined for 'home-link', you should change its definition to include:
:original => '79d342a6fd7281d8499d3a5ee5480f416f733e98'
these are my overrides files:
update_ordes.rb
Deface::Override.new(:virtual_path =>"spree/orders/edit",
:name => "continue_shopping",
:replace => "erb[loud]:contains('link_to t(:continue_shopping), products_path')",
:text => "<%= link_to t(:continue_shopping), products_path, :class => 'btn btn-primary' %>")
auth_login_bar.rb
Deface::Override.new(:virtual_path => "spree/shared/_nav_bar",
:name => "auth_shared_login_bar",
:insert_before => "li#search-bar",
:partial => "spree/shared/login_bar",
:disabled => false,
:original => 'eb3fa668cd98b6a1c75c36420ef1b238a1fc55ac',
:sequence => {:after => "auth_shared_login_bar"})
update_header.rb
Deface::Override.new(:virtual_path => "spree/shared/_header",
:name => "header_background",
:replace => "div#spree-header",
:text => '<div class="container">
<header id="header" class="row" data-hook>
<%= render :partial => "spree/shared/nav_bar" %>
<%= render :partial => "spree/shared/main_nav_bar" if store_menu? %>
</header></div>')
update_menu.rb
Deface::Override.new(:virtual_path => "spree/shared/_main_nav_bar",
:name => "home-link",
:remove => "li#home-link")
Deface::Override.new(:virtual_path =>"spree/shared/_nav_bar",
:name => "main_menu",
:replace =>"nav#top-nav-bar",
:text => '<nav id="top-nav-bar" class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<div id="logo"><%= logo %></div>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right" data-hook>
<li id="search-bar" data-hook>
<%= render :partial => "spree/shared/search" %>
</li>
</ul>
</div>
<!-- /.navbar-collapse -->
</div>
<!-- /.container -->
</nav>'
)
I also added the gem 'spree_bootstrap_frontend'
I do not get the changes done for the spree/orders/edit file
how should i fix this issue??
Original
The no original warnings are exactly what they say. You need to add the original option to your update_header.rb file. Also, your original hash value for auth_shared_login_bar is outdated and hence you need to either update that, or change to the exact original block you are using.
Sequence
Sequence option is used to know the order of overrides, when different overrides are being applied and the order matters. However, in auth_shared_login_bar, you are giving the reference of sequence to itself, causing a circular dependency. You should either remove that or give any other override this one depends on (For example :sequence => 'main_menu')

Simple form submit button not working

somehow my form is not working and I dont know why. Heres my code:
<%= simple_form_for #cr, url: edit_cr_path do |f| %>
<hr>
Design Office Involvements<br>
<%= f.collection_check_boxes :design_office_ids, DesignOffice.all, :id, :sub, {:item_wrapper_class => 'checkbox_container'} %>
<hr>
Procurement Involvements<br>
<%= f.collection_check_boxes :procurement_ids, Procurement.all, :id, :sub, {:item_wrapper_class => 'checkbox_container'} %>
<hr>
Installation Involvements<br>
<%= f.collection_check_boxes :installation_ids, Installation.all, :id, :sub, {:item_wrapper_class => 'checkbox_container'} %>
<hr>
<div class="row">
<div class="col-md-6">
Assessment Status
<%= f.input :assessment_status, :collection => [['Impacted','Impacted'],['Not impacted','Not impacted'],['Under assessment','Under assessment'],['New','New']], label: false, selected: ['New', 'New'] %>
</div>
<div class="col-md-6">
<div style="float: right">
<%= f.button :submit, 'Save' %>
</div>
</div>
</div>
<br>
<% end %>
Controller methods looking like this:
class CrsController < ApplicationController
def edit
#cr = Cr.find(params[:id])
end
def update
#cr = Cr.find(params[:id])
#cr.update_attributes(cr_params)
redirect_to edit_cr_path(#cr)
end
private
def cr_params
params.require(:user).permit(:id, :assessment_status)
end
end
And routes like this:
EndToEndManagement::Application.routes.draw do
get '/cr/:id', :to => 'crs#edit', :as => 'edit_cr'
put '/cr/:id', :to => 'crs#update'
patch '/cr/:id', :to => 'crs#update'
end
And thats the html code rails makes of my submit button:
<div class="col-md-6">
<div style="float: right">
<input class="btn" name="commit" type="submit" value="Save" />
</div>
</div>
I think the submit button is not correctly attached to the form but I tried to move it and clear some divs but nothing worked.
Best regards.
EDIT:
Thats what I tested
Removed my routes in routes.rb and replaced it with resources :crs and changed my first line in the form to <%= simple_form_for #cr do |f| %>. Didnt work!
Changed my simple_form to normal form. Didnt work!
Wrote a whole testapp with a scaffold and this form an it worked but I dont know why so I added part by part to my actual app and nothing made it working.
Found my mistake! Not that it would be so mind blowing but I will still post it :D
Had this small mistake in my application.html.erb
<div style="font-size: 1.3em"
<%= yield %>
</div>
Changed it to:
<div style="font-size: 1.3em">
<%= yield %>
</div>
And now it works fine.
It does not seem as edit_cr_path is the right url to go when you're trying to save a form.
You'll need another route:
post '/crs', :to => 'crs#create'
In your view, you probably won't need the url option as Rails can infer just looking at the object.
<%= simple_form_for #cr do |f| %>
But your object needs to be a new instance coming from your controller:
class CrsController < ApplicationController
def new
#cr = Cr.new #or whatever else to initialize the object
end
def create
#save the instance here
end

rails nested forms parts doesn't save altough the are permitted

i am programming in rails 4. I have done a nested form that addsnested attribuets by JavaScript , following
railscasts.
I have a feast. it has many dishes through courses and users through participations.
each users get feast assignments like that :
participations has many dishes through obligations.
My question is : why does it not save? the feast saves but the nested form parts do not...
basically I guess it is a problem with strong params somehow, or it should be in the controller or model. so I pasted them first . I pasted the HTML generated by the program - only the relevant part at the end so to make the question not too long somehow.
thanks
this is the code:
Class Feast < ActiveRecord::Base
mount_uploader :image, ImageUploader
has_many :participations, dependent: :destroy
has_many :users, :through => :participations
has_many :courses, dependent: :destroy
has_many :dishes, :through => :courses
accepts_nested_attributes_for :participations,
:allow_destroy => true
accepts_nested_attributes_for :courses,
:allow_destroy => true
and participations:
class Participation < ActiveRecord::Base
belongs_to :user
belongs_to :feast
has_many :obligations, dependent: :destroy
has_many :dishes, :through=> :obligations
has_many :groceries, :as => :needed
accepts_nested_attributes_for :obligations,
:allow_destroy => true
end
the program is complicated so in the end I of this question I will post the HTML created for one participant ,one dish and one assignment(=obligation) just so it is seen that the program works fine.
here are my nested forms - their values are updated and inserted by js.
course fields partial:
<%= link_to_function "remove","remove_fields_dish(this)", :class => "cl_both" %>
<%new_object = Feast.reflect_on_association(:courses).klass.new%>
<%= f.fields_for(:courses, new_object, child_index: "new_course", class: "fields") do
|fc| %>
<%=fc.hidden_field(:dish_id)%>
<%=fc.hidden_field(:_destroy,value: false)%>
<%end%>
participation fields partial:
<%= link_to_function "remove","remove_fields_dish(this)", :class => "cl_both" %>
<%new_object = Feast.reflect_on_association(:participations).klass.new%>
<%= f.fields_for(:participations, new_object , child_index: "new_course", class: "fields") do
|fc| %>
<%=fc.hidden_field(:dish_id)%>
<%=fc.hidden_field(:_destroy,value: false)%>
<%end%>
obligation fields partial:
<%new_object = Participations.reflect_on_association(:obligations).klass.new%>
<%= fp.fields_for(:obligations, new_object , child_index: "new_obli", class:
"fields") do |fpo| %>
<%= fpo.hidden_field(:dish_id) %>
<%= fpo.hidden_field(:_destroy,value: false) %>
<%end%>
my controller feasts_controller:
class FeastsController < ApplicationController
def list
#user_feast_m=Feast.joins(participations: :user).where(participations: {manager:
true}).to_a
#user_feast_p=Feast.joins(participations: :user).where(participations: {manager:
false}).to_a
end
def show
#feast=feast.find(params[:id])
#users=#feast.users
#dishes=(Dish.joins(obligations: {participation: :feast}).where(feast:
{id:#feast.id }).to_a + #feast.dishes).compact
end
def new
#feast= Feast.new
#myself = User.find(session[:user_id])
respond_to do |format|
format.html
format.js
end
end
def create
#feast = Feast.new(feast_params)
if #feast.save
flash[:notice]="the feast has been saved. all participants will get invitations and
assignments. hope they answer soon"
redirect_to(:action=>'list')
else
render('new')
end
end
def update
end
def edit
#feast=feast.find(params[:id])
#users=#feast.users.sort{|user1,user2| user2.manager <=>
user1.manager}.sort_by{|user| user.name}
#dishes=(Dish.joins(obligations: {participation: :feast}).where(feast:
{id:#feast.id }).to_a + #feast.dishes).compact
end
def delete
#feast=Feast.find(params[:id])
end
def destroy
end
private
def feast_params
params.require(:feast).permit(:id, :name, :image, :feast_place,
:feast_time,courses_attributes: [:id,
:dish_id,:_destroy,:feast_id],participations_attributes: [:id,:feast_id,
:user_id, :_destroy],obligations_attributes: [:id, :dish_id, :_destroy,
:participation_id])
end
end
this is the HTML generated:
<form accept-charset="UTF-8" action="/feasts/create" enctype="multipart/form-data"
method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8"
type="hidden" value="✓"><input name="authenticity_token" type="hidden"
value="llJ73mQ6yIZHKvs1EDHnVbjc1nIGlWN2eCirXwiCgCs="></div>
#+> some input fields for the feast goes here
<br><br>
<label for="feast_feast place">feast_place</label><br><br>
<input id="feast_feast_place" name="feast[feast_place]" type="text"> <br><br>
upload image file <br><br>
<input id="feast_image" name="feast[image]" type="file"> <br><br>
<h2>participants
<u>
<a class="right" data-content="<br />
<a class="cl_both" href="#"
onclick="remove_fields(this); return false;">remove</a>
<input id="feast_participations_user_id" name=";feast[participations][user_id]"
type="hidden" />
<input id="feast_participations__destroy" name="feast[participations][_destroy]"
type="hidden" value="false" />
<div data-obcontent='
<input id="feast_participations_obligations_attributes_new_obli_dish_id"
name="feast[participations][obligations_attributes][new_obli][dish_id]"
type="hidden"/>
<input id="feast_participations_obligations_attributes_new_obli__destroy"
name="feast[participations][obligations_attributes][new_obli][_destroy]"
type="hidden" value="false" />
' >
</div>
" href="#" id="try" onclick="add_par(); return false;">
<img alt="Photo Gallery" height="100" src="/assets/add_participants.png"
width="100">
</a> </u>
</h2>
<br><br><br>
<div data-myid="3" data-myimage=""image":{"url:"/uploads/user/image/3/el4.jp"}}" data-
myname="elad bezalel" id="par">
<table>
<tbody><tr>
<th>participant</th>
<th>assignment</th>
</tr>
<tr><td><div class="user_block ui-droppable" style=""><a href="/users/show?
id=7" id="1404733550784"><img alt="user picture"
src="/uploads/user/image/7/Yemenite.gif" height="100" width="100">
<br>amit</a><br>
<a class="cl_both" href="#" onclick="remove_fields(this); return
false;">remove</a>
<input id="1404733550977" name="feast[participations][user_id]"
type="hidden" value="7">
<input id="1404733554049" name="feast[participations]
[obligations_attributes][1404733554050][dish_id]" type="hidden"
value="140473354199">
<input id= "feast_participations_obligations_attributes_1404733554050__destroy"
name="feast[participations][obligations_attributes][1404733554050][_destroy]"
type="hidden" value="false">
<input id="feast_participations__destroy" name="feast[participations]
[_destroy]" type="hidden" value="false">
<div data-obcontent="
<input id="feast_participations_obligations_attributes_new_obli_dish_id"
name="feast[participations][obligations_attributes][new_obli][dish_id]"
type="hidden" ></div>
<input id="feast_participations_obligations_attributes_new_obli__destroy"
name="feast[participations][obligations_attributes][new_obli][_destroy]"
type="hidden" value="false" />
">
</div>
</div></td><td><dfn>e </dfn><img
alt="cancel - x" class="x-pic" height="30" src="/assets/x-blue.png" width="30">
</td></tr></tbody></table>
</div>
<br><br><br><br><br><br>
<h2>dishes
<u>
<a class="right" data-content="<br />
<a class="cl_both" href='#' onclick='remove_fields_dish(this); return
false'>remove</a>
<input id="feast_courses_dish_id" name="feast[courses][dish_id]" type="hidden" />
<input id="feast_courses__destroy" name="feast[courses][_destroy]"type="hidden"
value="false" />
" href="#" id="add_course" onclick="add_course(); return false;">
<img alt="Photo Gallery" height="100" src="/assets/add_dish.png" width="100">
</a> </u>
</h2>
<br><br><br>
<div id="course">
<table>
<tbody><tr><td><div class="dish_block ui-draggable ui-draggable-handle"
style="position: relative; top: 0px; left: 0px;"><a href="/dishes/show?id=9"
id="1404733541991"><img alt="dish picture"
src="/uploads/dish/image/9/IMG_0012.JPG" height="100" width="100"><br>e</a><br>
<a class="cl_both" href="#" onclick="remove_fields_dish(this); return
false;">remove</a>
<input id="1404733542182" name="feast[courses][dish_id]" type="hidden" value="9">
<input id="feast_courses__destroy" name="feast[courses][_destroy]" type="hidden"
value="false">
</div></td></tr></tbody></table>
</div>
<br><br>
<input name="commit" type="submit" value="initiate feast">
</form>
why does the nested parts not save?
I don't know the problem, but here are some things I would do to debug and narrow down your issue:
In your controller, raise feast_params.inspect. Do that match your expectations?
In a rails console session, try to create nested models (Feast.new(participations_attributes: {...})).
so here it goes:
i tried 2 plugins and they didn't work so i figured that i am doing something wrong with the
general form.
i used matched routes . as i changed to REST routes everything works fine.
probebly the previous form decleration line :
<%= form_for(:feast, :url => {:action => 'create'}) do |f| %>
was lacking the #feast variable so it can append to it the nested parts.
so maybe there is a way to fix it even with matched routes maybe something like:
<%= form_for(:feast, #feast, :url => {:action => 'create'}) do |f| %>
but since
i change to REST routes its working and i don't bother to check.

Using dropdown selector to change paths in Rails 4

I have a dropdown selector next to a search box in my navigation bar.
<select>
<option> All </option>
<option> Ask </option>
<option> Offer </option>
</select>
<form class="navbar-form navbar-right">
<%= form_tag(i_want_to_choose_this_path, :method => :get) do %>
<%= text_field_tag :search, nil,
{:id => "search-query-2", :placeholder => "Search favors..."} %>
<%= hidden_field_tag :use_keywords, "true" %>
<%= hidden_field_tag :wide_search, "true" %>
<% end %>
</form>
How can I use the selected option to change the path the search form will route to, to either asks_path, offers_path or all_path? The options are just words that relate to the paths I want to choose. They do not exist in any models. I looked at category_select, but it seems to require that my options are related to a model, which they don't, and I'm not sure how they would, because the paths point to different models.