I am developing a web application in Cl-who, Hunchentoot, and Common Lisp that will need to process customer orders. Since they could obviously order more than one item, I figured a Checkbox would make the most sense. However, the issue is when I define an easy-handler, it doesn't receive the array of results like an array in PHP if you have a series of Checkboxes with the same name and different values. Instead, it treats the variable as a String, so I cannot iterate over each Box that was checked. Here is a snippet of my code:
(:input :type "checkbox" :name "food[]" :value "cheese balls")
(:input :type "checkbox" :name "food[]" :value "fries")
(:input :type "checkbox" :name "food[]" :value "hamburger")
Here is the handler I have set up (maybe I need to use the loop macro here?) This is just a sample because I will obviously process each argument passed to the easy-handler when I figure out this problem:
(define-easy-handler (process-order :uri "/process-order")
(customer-name customer-address customer-city customer-phone order-type food[])
(standard-page (:title "order results"
:href "file.css")
(:h1 (if food[]
(dolist (x food[])
(:li (fmt "We see that you want ~A~%" x)))))))
Those are just three potential inputs that someone could check. So lets assume that a customer checks all three... Only cheese balls would return because Lisp is treating the name "food[]" as an individual string. What I mean by that is that in PHP that variable for name ("food[]") would be processed as if it were an array. So in HTML and PHP it would look something like this:
<input type="checkbox" name="food[]" value="cheese balls" class="check"/>
<input type="checkbox" name="food[]" value="fries" class="check"/>
<input type="checkbox" name="food[]" value="hamburger" class="check"/>
Assuming a customer selected all three Checkboxes, I could do something similar to this in PHP:
if( isset( $_POST['food'])) {
foreach ( $_POST['food'] as $food){
echo $food;
}
}
It is not clear how you'd achieve similar functionality in Common Lisp with Cl-WHO and Hunchentoot however. The only other alternative I can think of is passing like 30 parameters to the easy-handler, but that sounds like the least efficient way to solve this problem. I know that there is also a CL form processing library, but I was hoping to avoid going down that route, although I will if that's the only possible solution. Giving each checkbox a different name seems like the worst possible way to solve this.
After further reading the documentation, you can alter the parameter type that the easy handler expects to receive. As soon as it sees that it is a list in the parameter definition, it treats it as a List. I simply changed my food parameter to this:
(food[] :parameter-type 'list)
And it treats it as if it where a list and retrieves multiple results from my CheckBoxes.
Related
I'm trying to have an if else statement in the controller to do something if the check_box_tag is checked and something else if it isn't checked.
<%= check_box_tag "apply[]", 1, false %>
If it is checked and the form is submitted "apply"=>["1"] is passed as a parameter, if it isn't checked nothing is sent.
Can I have a "apply"=>["0"] passed as a param if it isn't checked?
The check_box_tag indeed does not use the hidden field so it does not send anything in case the box is unchecked (unlike the check_box helper, which is nevertheless still not useful in case of an array param, as Meier notes above).
If you are trying to use your checkbox in a similar way as in this SO question (i.e. to send a user-selected array of ids for example), the simple solution might be to react on an empty param in the controller. Something in the way of:
params[:apply] ||= []
If, on the other hand, you wanted to use the checkboxes as an ordered array where each value would be determined by its constant position in the array, either true or false, (i.e. if you wanted to get something like this in the apply param: [0, 1, 0, 0, 1]), this wouldn't work. You'd have to choose a different approach, e.g. use the checkboxes with a hash param instead of array.
The rails guide has a warning box about this special case:
http://guides.rubyonrails.org/form_helpers.html
Array parameters do not play well with the check_box helper. According
to the HTML specification unchecked checkboxes submit no value.
However it is often convenient for a checkbox to always submit a
value. The check_box helper fakes this by creating an auxiliary hidden
input with the same name. If the checkbox is unchecked only the hidden
input is submitted and if it is checked then both are submitted but
the value submitted by the checkbox takes precedence. When working
with array parameters this duplicate submission will confuse Rails
since duplicate input names are how it decides when to start a new
array element. It is preferable to either use check_box_tag or to use
hashes instead of arrays.
Example, i made a form like this
<form name="register" method="post" enctype="multipart/form-data">
<p><h3>User check</h3></p>
<p>admin ID: <input type="text" name="userid"></p>
<p>admin Pass: <input type="password" name="password"></p>
<input type="submit" name="apply" value="Submit"></p>
<p> </p>
</form>
and my manager wants to change this form to rails form template like this,
<%= form_for(:model) do |form| %>
<p>
<%=form.label :input%>
<%=form.text_field :input, :placeholder => 'Enter text here...'%>
</p>
<%end%>
My question is, it works fine with html based front code. Why do i have to change this to rails code? I just want to keep my front-end code...I don't know why i have to change this :(. Also, I'm new on Ruby on Rails. That is the main reason. I dont' want to change the existing code, if it is working.
I really hate this job. I have to translate all the attributes to the rails code and that makes me really exhausted :(
Form builders are here to help
Form helpers are supposed to make your life simpler. They are quicker to write than their pure html alternative, provided you don't write pure html first.
They also provide a lot of easy implementations for difficult integration pieces, like :
displaying a date selection select group
mirroring the fact that a check box has been unchecked in POST params
automatically adding multipart param on form if you add a file input (not actually difficult to achieve, but easy to forget)
... and many more
Further development
All of this is about comfort, and you may think you could avoid it if you already have a perfectly working pure html implementation.
But what happen if someone later has to add a date select input in your form ? She will have to use the rails helper, since it saves a lot of time in controller part to set date in database. But she won't be able to leverage form builder, since you haven't used it.
Now, she has to choose between using a non builderdate_select tag mixed in pure html or ... to rewrite your form completely. As you may realize, mixing different styles is generally considered ugly, and we don't like ugly in ruby.
Security
Form tag helpers also provide an important security measure : CSRF protection. Every time you use a rails helper to create a <form> tag, it automatically adds an hidden input containing a secret key. That key has to be posted with form data to prove request originated from current website.
If you use plain html forms, you won't have this security. You could of course add the token manually using the correct method, but this would again be more time wasting than simply using form helpers.
Bottom line
The main problem is that you write pure html before using rails helpers - that is what is wasting time.
Some benefits of using Rails form helpers are:
Consistent naming of input elements names and ids
i18n support for labels
generated URL with form_for is less error prone
Better handling of checkboxes
Nice helpers like options_for_select
Less typing
That last ones might be my favourite: less typing.
I just managed to do a decimal migration.
But all of the sudden a weird button appeared next to the field.
Any idea how i can remove it or maybe the name of that weird thing?
Its on the right side of the field. And it has arrow up and down.
(I´m very new to coding)
This is the code
<%= f.input :phone, as: :decimal, placeholder: "Phone Nr.", label: "Contact", input_html: { rows: "1"} %>
Sorry, not allowed to post images yet.
It's a numeric input from HTML5, you may see this for description.
You may control input type by setting as parameter, possible values.
For most fields you may omit it, formtastic will guess correct input type by attribute type or name.
I think it would expect the phone attribute to be of a string type. If you need some why to keep it numeric but normal phone input is required, force it with as: :phone. But then you should have some preprocessing for this value before writing it to attribute.
The weird button is a part of number input. Read here about most common input types available in HTML5. It's purpose is to enter a decimal number. HTML5 introduced new input semantics so instead of boring box your browser will render additional controllers on top of the input depending on it's type.
What you probably want is a tel input. Rails provide <%= telephone_field() %>. Here is the list of all form helpers available in Rails.
Also consider using string for your phone number and validate it on model instead
I am well aware that you use underscores for data attributes with hyphens ("data_bind" instead of "data-bind", in the object), and they automatically get replaced with hyphens. But I have run into the problem where you can't do this underscore "hack," if the attribute ends with "name". So I have tried both of these, but neither work:
#Html.TextBoxFor(model => model.Street, new { data_encrypted_name = "street" })
#Html.TextBoxFor(model => model.Street, new { #data_encrypted_name = "street" })
When I view the HTML that is generated, for both cases above, it generates:
<input data-encrypted- id="ViewModel_Street" name="ViewModel.Street" type="text" value="" />
At first, I thought this might have something to do with multiple underscores/hyphens, but I tried two more test cases, to see what would happen, and they both worked just fine:
#Html.TextBoxFor(model => model.Street, new { data_encrypted_namme = "street" })
#Html.TextBoxFor(model => model.Street, new { data_name_encrypted = "street" })
So this problem is definitely related to having "name" at the end of the attribute.
Am I doing something wrong or missing something, or is this a bug in how .NET converts the attributes?
(For clarification, we use Braintree Payments, and they require the use of the "data-encrypted-name" attribute on certain inputs, so we can't just choose another attribute name.)
Thanks to Tommy for testing the behavior I described and finding it wasn't a bug for everyone.
After Tommy wrote this, I looked at the Helper we were using. I realized that we were actually using an Extension method called "NameLessTextBoxFor" (which we found here: How to extend html.textboxfor to remove the name attribute?), which removes the name="" attribute from the input before displaying it. I should have confirmed this before posting, but didn't recognize it could affect the HTML attributes passed into it.
And lo and behold, as you would probably expect, the functionality of this method was also cutting off any attribute that contained name="". It was doing a very simple search and replace on that text and removing it. So that was the issue here.
Thanks for your time and attention to this issue and apologize I didn't catch this myself.
I need to build something like what gmail does for it's labels... It has a button that when pressed pops up a scrolling list displaying the labels with checkboxes for selection.
I'd like to hear about approaches to do the popup and how to place it right under the button.
Also, I'd like to be able to observe the checkbox select/deselect events and take action, so advice on that part would also be appreciated... otherwise, I guess I'll have to put a form with a submit button and handle the new selections when the user submits.
If the checkbox list is static, you can do all this directly in the rendered action. Otherwise, two approaches are possible:
Use button_to_remote to retrieve an action displaying the popup and also serving the necessary js;
Use button_to_function to retrieve some XML or json (at your option) from an action, with the necessary labels and values for checkboxes, then render the popup.
The first may be easier to do if you're not familiar with all this, while the second is way more efficient, as only data is passed through the asynchronous call, and not markup nor javascript.
About your last question, if (un)checking the checkbox must result in a server side action, prototype_helper provides a convenient observe_field function, to be used like this:
<%= check_box "foo", "bar" %>
<%= observe_field "foo_bar", :url => {:action => :some_action, :controller => :some_controller} %>
If the (un)checking can be managed on client side, you can simply use:
<%= check_box "foo", "bar", { :onclick => "someFunctionToDoWhatINeed(someArg);"} %>
Just two notes:
JavascriptHelper and PrototypeHelper are just this, helpers: they allow you to do some things with a very simple syntax and are great, as long as they are helping; when they are no more, feel free to drop them and go for plain javascript.
I've used prototype for a while, but then I fell in love with jquery; you may want to take a look at it.
Please edit your question or comment my answer if I didn't understand your question and/or was unhelpful.