This is something that leads me to waste hours and I wish I knew why. I've found lots of examples (not all answered) where forms are not being submitted, it works on a webpage, but not in capybara. things like find/xpath work in the irb.
web page
file box with a upload button, attaching the file works (i'm using poltergeist render to see that file name is attached)
debugging / options tried
find () works e.g. in irb it returns an object: Capybara Element tag=input
if i attempt to "visit '' it returns {"status"=>"fail", "click"=>{"x"=>124, "y"=>283}} [nothing in the log that action called. DEFINITELY works in development environment]
click_on 'Upload' fails: {"status"=>"fail", "click"=>{"x"=>124, "y"=>283}}
find_button('Upload').click: {"status"=>"fail", "click"=>{"x"=>124, "y"=>283}}
find("#upload_bill_button1").trigger("click"): returns "click"
i have tried exec_script of javascript checkBill() . page.execute_script('checkBill()'): returns nil
find(:css, '#upload_bill_button1').click . returns: {"x"=>124, "y"=>282}
nothing in the logs to show the action is being completed
i have
js=>true as its a javascript submit (does a test first, code below).
made sure all ids are unique
capybara::DSL added
system setup
Mac ox X
poltergeist (working for all my other tests)
ruby 1.9.3
phantom 1.9.2
is there further debug to figure out the problem ? other logs i'm missing?
any guidance much appreciated
<div class="row">
<div class="large-10 columns" >
<%=form_tag( "/upload_bill", :method=>:post, :multipart => true, :id => "form_upload1") do -%>
<fieldset>
<legend>Select your bill file</legend>
<%=file_field_tag 'bill', :onclick => "checkBill()" -%>
<div class="large-2 columns" >
<!-- TODO: make the browse button the zurb class type -->
<%- if params[:action].eql?( 'index')%>
<%=submit_tag "Upload", :onclick => "checkBill();return false;", :id => "upload_bill_button1", :class => "button postfix" -%>
<% end %>
</div>
</fieldset>
<% end %>
</div>
</div>
<%- if params[:action].eql?('import_bill')%>
<%=link_to (image_tag "/images/btn-uploadbill.png"), "#", :onclick=>"checkBill();return false;", :id => "upload_bill_button2" -%>
<%=link_to (image_tag "/images/btn-cancel.png"), root_path %>
<%- end %>
<script type="text/javascript">
function checkBill(){
var bill = $("#bill").val();
if(bill.split('.').reverse()[0]=="csv"||bill.split('.').reverse()[0]=="pdf"||bill.split('.').reverse()[0]=="pdftranslatedtxt"){
//success bill supported, data send to app
jQuery('#form_upload1').submit();
}
else if(bill==""){return false; }
else{// return error wrong format of bill alert('We only currently support PDF or CSV file format.')
}
}
</script>
UPDATE
I have the code working on some instance of this page. I have also have one situation where the find/trigger is working (the logs show actions, but the poltergeist:render shows no page update)
so, rspec function is
def new_import_bill(billfile)
path = DATA_TEST+billfile
attach_file("bill", path)
find("#upload_bill_button1").trigger("click")
end
I have debugged the page output e.g.
puts page.html
and there is no difference between the page html that works and the pages that do not work., but in certain situations it refuses to click or the poltergeist.render does not update.
as per this poltergeist bug (https://github.com/jonleighton/poltergeist/issues/209) I have tried removing full:true. No difference
has anyone else come across these inconsistences?
Related
Context: a form has a collection_select, but without a value that interests the user.
A second form allows to create a new entry that would populate the collection_select with a desired value.
Class Article has_many :tags
The create turbostream does render the object, but the form does not display the change & I suspect it is due to the atomicity of the form. the IDed div tag was tried both outside and inside the form_fields tag to the same neutered effect.
<%= form.fields_for :tags do |tag| %>
<div id='tags'>
<%= f.collection_select(:tag, #tags, :id, :name) %>
</div>
<% end %>
The turbo_stream file tris to replace the target. If f.collection_select is used, this generates an error as rails, handling the snippet does not know of the form's existence. Using select_tag, a tag is rendered and delivered but the div is not refreshed
<%= turbo_stream.replace "tags" do %>
<div class='fade-in-div'>
<%= select_tag :tag, options_from_collection_for_select(#tags, :id, :name) %>
</div>
<% end %>
How can these options for select be updated with hotwire?
Functional answer that does not answer the question:
• the new data needs its own field
• make that an allowed attribute with the relevant accessor atrr_accessor
• process the new value
• update the record
• choose preferred path: redirect or turbo_stream a partial as a replacement of entire form.
I have this form:
= form_tag(path, name: "name") do |f|
= hidden_field_tag "abc", content
= submit_tag "" do
%i.icon.ion-android-sync
As you can see, I am trying to put an Ionicon inside the Form Submit tag.
I've tried a bunch of ways, none of which worked.
With the given example I get an empty button with an approximate width of 3px.
Is it possible to embed a child in a submit_tag? If, how would you go about doing so?
Thanks a lot for each answer!
The short answer is "no". However, you can make a button with type of "submit" that'll do the same thing and allow you to put content in it:
%button{type: "submit"}
%i.icon.ion-android-sync
No the Rails submit helper won't let you do that.
I use a custom submit helper in my app :
# Render a form submit button
# === Params
# +value+:: Value of the input/commit button, used for route constraints
# +text+:: Text for the button
# +:html_options+::
def submit(value=nil, text=nil, html_options={})
text ||= 'Submit'
html_options[:name] ||= 'commit'
html_options[:type] = 'submit'
html_options[:data] ||= {}
html_options[:data][:disable_with] ||= 'Please wait'
html_options[:autocomplete] = "off" # https://github.com/rails/jquery-ujs/issues/357
content_tag(:div, class: 'form-submit-wrapper') do
button_tag(html_options){ block_given? ? yield : text }
end
end
You can just pass whatever HTML you want in a block (sorry this is ERB, I'm not really familiar with HAML)
<%= submit do %>
<i class="icon ion-android-sync"></i>
<% end %>
The first two params are only helpful if you have several submit buttons for your form
<%= submit('preview_action', 'Preview result') do %>
<i class="icon ion-android-sync"></i>
<% end %>
<%= submit('really_do_action', 'Do it for real') do %>
<i class="icon ion-android-sync"></i>
<% end %>
I have a page type (ProducerReport) which acts like a summary page - it gets data from individual pages (Shows) and lists them all on one page with the main info from each article.
Using ChildrenOf() made it really easy and simple, I thought wow SilverStripe will do all the work for me all I have to do is structure and style it!
But then tragedy struck...
In Shows I have a DataObject linked by $has_many which allows users to add key people such as contacts etc for each individual article, this is done via GridField (ShowsContacts).
At first I kind of assumed that simply adding the necessary variables would get the data from ShowContacts - this didn't work.
Then in the view I took a shot in the dark and tried using $ID which actually worked and returned the ID of the post.
So I went ahead I added this into the ProducerReport controller which I hoped would get the job done, allowing me to perform a query to get the relevant contacts and loop it within in the ChildrenOf loop.
However, the controller doesn't do anything while in the loop. The only time it outputs anything is when I put the outside of the loop.
ProducerReport.php
class ProducerReport_Controller extends Page_Controller {
# Get the Show Contacts for the Show, based on ShowsID
public function something($SiteID){
# Needs to be cast to int as param comes in as string
$x = (int)$SiteID;
var_dump(ShowsContact::get()->find('ShowID', $x)->Role);
}
}
ProducerReport.ss
<div class="producer-report">
<% loop ChildrenOf(current-shows).sort('PercentageComplete', 'DESC') %>
<div class="show">
<div class="banner">
<% if $ReportImage %>
$ReportImage
<% else %>
<img src="/assets/_placeholders/producer_report_cover.png" />
<% end_if %>
<h2>$Title <span>($ProjectCode)</span></h2>
</div><!-- . banner -->
<a class="hub-link" target="_blank" href="http://website.com?job=$ProjectCode">Hub</a><!-- . hub-link -->
<div class="stats">
<h3>Show Statistics</h3>
<dl>
<dt>Client</dt>
<% if $Client %>
<dd>$Client</dd>
<% else %>
<dd>None set</dd>
<% end_if %>
</dl>
<dl>
<dt>Percentage Complete</dt>
<% if $PercentageComplete %>
<dd>$PercentageComplete%</dd>
<% else %>
<dd>-</dd>
<% end_if %>
</dl>
</div><!-- . stats -->
</div><!-- . show -->
<!-- Here I need to retrieve info of the contacts belonging to the page -->
<!-- Inside the ChildrenOf loop, this DOESNT output anything -->
$something($ID)
<% end_loop %>
<!-- This outside the loop DOES output a job role -->
$something(84)
</div><!-- . producer report -->
EDIT - Additional code
This here is what the ProducerReport gets data from, all direct data for this Model appears in that ChildrenOf loop; The ShowsContact data isn't accessible and if I try to query using the $something($ID) functionality it doesn't work when used inside the loop.
Shows.php
class Shows extends Page {
private static $db = array(
'ProjectCode' => 'Varchar(4)',
'Client' => 'Varchar(255)',
'PercentageComplete' => 'Int'
);
private static $has_one = array(
'ReportImage' => 'Image'
);
private static $has_many = array(
'ShowsContacts' => 'ShowsContact'
);
public function getCMSFields(){
# GridField / Show Contacts
$conf = GridFieldConfig_RelationEditor::create();
$gridField = new GridField('ShowsContact',
'Show Contact List',
$this->ShowsContacts(), $conf);
$fields->addFieldsToTab('Root.Content.ShowContact', array(
$gridField
));
return $fields;
}
}
class Shows_Controller extends Page_Controller {
# Get key people from ShowsContact class // input via ShowsContact GridField
# THIS HERE is the data that I need displayed on ProducerReport
public function getKeyPeople(){
if($this->ShowsContacts()->exists()){
$result = new ArrayList();
foreach($this->ShowsContacts()->column('MemberID') as $teamMemberID){
$member = Member::get()->byID($teamMemberID);
$result->add(new ArrayData(array(
'PictureURL' => $member->ImageURL,
'Role' => $this->ShowsContacts()->find('MemberID', $teamMemberID)->Role,
'Firstname' => $member->FirstName,
'Surname' => $member->Surname,
'Nickname' => $member->Nickname,
'Email' => $member->Email,
'Ext' => $member->Extension,
'Site' => Site::get()->byID($member->SiteID)->Title
)
));
}
return $result;
}
else
return null;
}
}
My question is - how would I get data from another page type as well as data that's linked to it by relationship if I am unable to do a loop within a loop - or am I doing something wrong?
AHHHH!! omfg!!!! Okay, so after taking many many shots at this issue I found out how to get this working.
The solution to this is to use $Top.[Method] inside the loop. I assume its because SilverStripe is doing it's own thing within the loop and for whatever reason becomes a bit blind. From what I understand - you have to tell the method to go outside the loop in order for it to see / use the Controller
Going from the code above in ProducerReport.ss and trimming it down for relevance to the question...
<% loop ChildrenOf(current-shows).sort('PercentageComplete', 'DESC') %>
...
$Top.something($ID) <!-- works perfectly, ID is passed. Output is as expected!
...
# Or when in a loop it'll be like so...
<% loop $Top.something($ID) %>
# ArrayList / ArrayData output...
<% end_loop %>
<% end_loop %>
I can't believe this took me so long to find a solution!
May anyone who gets stuck on something like this or anything similar find their way to this answer because I was honestly about to give up and rewrite everything for this page type and use queries to get all the data to put in the template...
Edit / Note: I've found that if you have a method called getUserName (for example) you cannot omit the 'get' when using it with $Top ... so in the template you need to put $Top.getUserName when using it
Not sure it's relevant if you think you've fixed your problem, but the something controller method (is that even used?) will never dump what you think it will as any DataObject::get() or DataList::create() ORM calls always return an instance of DataList, not an individual DataObject.
If you're trying to see what SS has from that query, try using ->first() instead, which as you might guess, returns the first DataObject (or DataObject subclass) in your list:
...
var_dump(ShowsContact::get()->find('ShowID', $x)->first()->Role);
For your template you could do this:
ProducerReport.ss
<% loop Shows %>
<% loop ShowsContacts %>
<%-- contact details here --%>
<% end_loop %>
<% end_loop %>
Where 'ShowsContacts ' is the name of the relation from shows to contacts
I'm on rails, using the 'twitter-bootstrap-rails' gem, version 3.2.2 which may or may not be relevant to the diagnosis here.
So basically I've used some documentation examples online to get a panel-collapsing functionality on a little data visualization application I've made using the chartkick gem. I got the collapsibility functionality, but now the charts inside of my collapsible divs are getting squeezed into 400px X 200px rect elements despite my instructions for height and width being added.
Here's what the charts should look like. These are the charts that have not been placed into collapsible div elements (I'm the real estate developer here as well so not worried about privacy w/ regards to data)
And here's what the squeezed charts inside of the collapsible divs look like:
What's even stranger is that I had to reload the page to get the bug to show itself, because in the time it took me to write this question, the chart had somehow fixed itself. Happens randomly but normally takes at least a minute. Sometimes I can get it to "fix itself" if I open up the web inspector and point to the elements. This is what it looks like after a spontaneous self-fix:
The self fix only worked for the already-collapsed div elements. The uncollapsed elements remain shrunken after being expanded, at least initially.
code for the index.html.erb page for the properties controller. Nothing proprietary here really.
<h1>Properties</h1>
<% #properties.each do |p| %>
<div class="panel panel-default">
<div class="panel-heading"><h3><%= p.name %> Hard & Soft Costs Per Draw</h3></div>
<div class="panel-body">
<% hard_costs = p.hard_costs %>
<% soft_costs = p.soft_costs %>
<% construction_contract_estimates = hard_costs.map(&:sv_construction_contract) %>
<%= construction_contract_estimates.pctg_change %> Change in Construction Contract Estimate from Draw 1 to Draw <%= hard_costs.last.draw_i %>
<%= column_chart [{:name => "Hard Cost Left to Go", :data => hard_costs.map{|hc| [hc.draw_i, hc.b2f_construction_contract.to_i]}}, {:name => "Hard Cost Draw", :data => hard_costs.map{|hc| [hc.draw_i, hc.cd_construction_contract.to_i]}}, {:name => "Total Hard Cost Estimate", :data => hard_costs.map{|hc| [hc.draw_i, hc.sv_construction_contract.to_i]}} ], :height => "800px" %>
<%= column_chart hard_costs.map{|r| [r.draw_i, r.cd_construction_contract] }%>
<%# collapsible column chart 1%>
<div class="panel panel-default" style="display: block;">
<% softcosts_pd_graph_id = "#{p.name.sanitize}_scpd_chart_id" %>
<div class="panel-heading">Soft Costs Per Draw Graph (<a href="#<%= softcosts_pd_graph_id %>" data-toggle='collapse'>Show/Hide</a>) (click twice to hide the first time)</div>
<div class="panel-body collapse" id="<%= softcosts_pd_graph_id %>">
<%= column_chart p.soft_costs.map{|sc| [sc.draw_i, sc.cd_total_soft_costs.to_i] } , :library => {:xtitle => "Draw #", :ytitle => "Soft Cost Draw", :width => "800px"} %>
</div>
</div>
<%# collapsible series of pie charts %>
<div class="panel panel-default" style="display: block;">
<% softcosts_pd_pies_id = "#{p.name.sanitize}_scpd_pies_id"%>
<%# figure out how to use glyph icons and use 'glyphicon-collapse-down' and '...-up' %>
<div class="panel-heading">Soft Costs Per Draw Pie Charts (<a href="#<%= softcosts_pd_pies_id %>" data-toggle='collapse'>Show/Hide</a>) (click twice to hide the first time)</div>
<div class="panel-body collapse" id="<%= softcosts_pd_pies_id %>">
<ul class="list-group">
<% p.soft_costs.each do |sc| %>
<li class="list-group-item">Draw <%= sc.draw_i %>:
<h4>Soft Cost Draw #<%= sc.draw_i %>: <%= number_to_currency sc.cd_total_soft_costs %> </h4>
<%= pie_chart sc.breakdown_chart_data.sort_by{|x,y| y}.reverse, :library => {:legend => {position: "right"} } %>
</li>
<% end %>
</ul>
</div>
</div>
</div>
</div>
<% end %>
Code taken from client web browser: gist
Thanks! Hope I've made it as easy as possible for someone to assist
Also, while we're on this subject of handling the rect boxes created by chartkick, does anyone know how to edit the height and width of the rect box serving as an outer container for the chart itself? There's too much buffer here.
I had the same problem with Chartkick in foundation-rails. The problem is that the resize event handlers are not triggered when expanding.
For example, I had the following code in a js file for my expandable elements:
$(function() {
$('tr.parent')
.css("cursor","pointer")
.attr("title","Click to expand/collapse")
.click(function(){
$(this).siblings('.child-'+this.id).toggle();
});
$('tr[class^=child-]').hide().children('td'); });
I added the following under the click event to trigger the resize event handlers:
var evt = document.createEvent('Event');
evt.initEvent('resize', true, true);
window.dispatchEvent(evt);
This works just fine:
$(function() {
$('tr.parent')
.css("cursor","pointer")
.attr("title","Click to expand/collapse")
.click(function(){
$(this).siblings('.child-'+this.id).toggle();
var evt = document.createEvent('Event');
evt.initEvent('resize', true, true);
window.dispatchEvent(evt);
});
$('tr[class^=child-]').hide().children('td'); });
There might be a better way to do this, but it's a good start.
New to rails, and am experimenting with changing default layouts.
It seems that the .field_with_errors class is always being added to my forms, when a field causes a validation error. The default scaffold CSS defined field_with_errors as:
.field_with_errors {
padding: 2px;
background-color: red;
display: table;
}
My question is: Why even use this .field_with_errors? Where is it even coming from? Same with a div with ID of notice to print success messages. Where is this coming from?... From my research both of these coming somewhere from ActionView::Helpers.
But what if I wanted to use my own custom styles for these? Do I have to write my own .fields_with_errors and notice classes in my application.css.scss file? I tried this and it works... But why do I have to jail myself to those class names? What if I wanted to call them something else? Can I do this?
Secondly, let's say I have my own custom CSS classes now (assuming it's possible -- which I hope it is)... What if I wanted to apply a bootstrap style to them? For example, bootstrap would use <div class="alert alert-success"> where Rails' scaffold would default to using <div id="#notice">... How can I make such changes in the most elegant way without simply making my own style with the same CSS code as Twitter's alert alert-success.... Isn't there a way in SASS (or through Rails somehow) to say, Success messages are printed with XYZ style and error fields are printed with ABC style... Like maybe in some config file?
Thanks!
Can I do this? yes.
The extra code is being added by ActionView::Base.field_error_proc. If you want to call something else and you're not using field_with_errors to style your form, You should override it in config/application.rb
config.action_view.field_error_proc = Proc.new { |html_tag, instance|
"<div class='your class'>#{html_tag}</div>".html_safe
}
Restart your server
Secondly, If you want to apply a bootstrap style to them, You can save your selection style on application_helper.rb
module ApplicationHelper
def flash_class(level)
case level
when :notice then "alert alert-info"
when :success then "alert alert-success"
when :error then "alert alert-error"
when :alert then "alert alert-error"
end
end
end
create file layouts/_flash_message.html.erb and paste this :
<div>
<% flash.each do |key, value| %>
<div class="<%= flash_class(key) %> fade in">
×
<%= value %>
</div>
<% end %>
</div>
and to call the flash you just render in view
<%= render 'layouts/flash_messages' %>
Example
On accounts_controller.rb create action
def create
#account = Account.new(params[:account])
if #account.save
# using :success if #account.save
flash[:success] = "Success."
redirect_to accounts_url
else
flash[:alert] = "Failed."
render :new
end
end
Put on top of accounts/index.html.erb and on top of form in accounts/_form.html.erb
<%= render 'layouts/flash_messages' %>
Result on index :
<div class="alert alert-success">
<button type="button" class="close" data-dismiss="alert">×</button>
Success.
</div>
Result on form :
<div class="alert alert-error">
<button type="button" class="close" data-dismiss="alert">×</button>
Failed.
</div>
#anonymousxxx answer seems to be correct in my opinion.
I would recommend you to use the twitter-bootstrap-rails gem (https://github.com/seyhunak/twitter-bootstrap-rails) for your css. check out the readme on github, this gem is really convenient.