With Rails 5, how to think about naming a form field to later be used be a Rails Controller#create method - ruby-on-rails

In Rails 5, I have the following model:
Talents.rb
id | Title
1 | Jumping
2 | Skipping
3 | Running
My API, returns Talents#Index like so:
[
{"id":1,"title":"Jumping"},
{"id":2,"title":"Skipping Rope"},
{"id":3,"title":"Running"},
{"id":4,"title":"Something Else"}
]
I then want to use the respond to build a form:
<div>
<label>Jumping</label>
<select name="Jumping">
<option></option>
<option value="1">XXX</option>
<option value="2">YYY</option>
</select>
</div>
....
My question is how should I be thinking about NAMING the talents in the form so that I can properly post the form to Rails to then record the user's response?
Do I need another field from the API with some type of Key? Or for select name, should I be using the ID?

I will do something like this:
<form name="my-form" method="post" action="/create">
<div>
<label>Jumping</label>
<input type="hidden" name="ratings[]talent_id" value="1"></input>
<select name="ratings[]rating">
<option></option>
<option value="1">Rating 1</option>
<option value="2">Rating 2</option>
</select>
</div>
<div>
<label>Skipping</label>
<input type="hidden" name="ratings[]talent_id" value="2"></input>
<select name="ratings[]rating">
<option></option>
<option value="1">Rating 1</option>
<option value="2">Rating 2</option>
</select>
</div>
<div>
<label>Running</label>
<input type="hidden" name="ratings[]talent_id" value="3"></input>
<select name="ratings[]rating">
<option></option>
<option value="1">Rating 1</option>
<option value="2">Rating 2</option>
</select>
</div>
<input type="submit" name="submit" value="Send">
</form>
Using ratings[] will create an array, which enables you tu use the same name for each select.
Adding an input with type hidden, will allow to specify which talent is being rated (the value of each input is the talent_id to be rated in that select).
For example, if a user selects the following:
Rating 2 for Jumper
Rating 1 for Jumping
Rating 1 for Skipping
Then the following parameters will be sent to your controller:
Parameters: {
"ratings"=>[
{"talent_id"=>"1", "rating"=>"2"},
{"talent_id"=>"2", "rating"=>"1"},
{"talent_id"=>"3", "rating"=>"1"}
]
}
Now, in your controller you could just iterate over params[:ratings] to create each object, maybe something like this:
params[:ratings].each do |rating|
rating_attributes = {
user_id: user, # use the appropriate `user_id`
rated_by: rater, # use the appropriate `rated_by`
talent_id: rating[:talent_id],
rating: rating[:rating]
}
Rating.create!(rating_attributes)
end
Of course you should optimize this method by, for example, handling errors instead of raising an exception (as create! does); but this will get you going.

Related

How keep value from input select after request?

I'm doing a search form in my site. And what i want is to keep on my inputs, the value selected by the user. It's ok for my checkbox, but i can't do it for select.
I show you my form first :
<select name="garde" id="garde">
<option value="">Choisir un type de garde</option>
#foreach($gardes as $garde)
<option value="{{$garde->id }}">{{$garde->garde }}</option>
#endforeach
</select>
<div class="flex items-center">
<input id="chats" name="chats" value="1" id="chats" type="checkbox"
#if(request()->chats) {{ 'checked' }} #endif>
<label for="chats" class="ml-3 text-sm text-gray-600">Chat</label>
</div>
I tried to use some :
<select blablabla>
<option value="{{$garde->id}}" #if(request()->garde) {{'selected'}} #endif/>{{$garde->garde}}</option>
</select>
So it's certainly good for the value, but it doesn't display the good option name. Always sending me the last value from the database (which is 3 in this case).
My controller
$garde = request()->input("garde");
$chats = request()->input("chats");
$g = Garde::where('id', 'like', "%$garde%")->pluck('id');
Annonce::when($g, function ($s) use ($g) {
return $s->where('garde_id', $g);})
->when($chats, function ($s) use ($chats) {
return $s->where('chats', $chats);})
Edit : Here the "%$garde%" was after trying another option, using "$garde" doesn't changed anything.
As i said, it's ok for checkbox, but for select i can not keep this value without doing a "bidouille" as we say in french ^^
<select name="garde" id="garde">
<option value="{{ request()->garde ?? '' }}">
#if(request()->garde == 1) Chez le Pet-Sitter
#elseif(request()->garde == 2) Visite à domicile
#elseif(request()->garde == 3) Chez le Pet-Sitter/En visite
#endif
</option>
#foreach($gardes as $garde)
<option value="{{$garde->id }}">{{$garde->garde }}</option>
#endforeach
</select>
But this is not a good practice i know it, and it's display 2 times the selected value ofc..
Have you got some ideas?
Maybe not using the pluck('id) in my controller is the key? But what is other way to do it?

how to set selected value in drop down menu depending on conditions

I have code with drop down menu. The object for this menu has few fields. Two of them are playerPosition and isFirstSquadPlayer.
If isFirstSquadPlayer is TRUE I need to display in menu player.playerPosition.
Trying on few ways but failed.
My controller:
public String players(#PathVariable long clubId, Model model) {
Club club = this.clubRepository.findByClubId(clubId);
model.addAttribute("players", this.playerRepository.findAllByPlayerClub(club));
return "players";
}
My HTML:
<select name="playerposition"
id="createnewplayerposition" th:value="${player.playerPosition}" required>
<option value="0">Select position for player</option>
<!--HERE NEED PROPER REQUEST -->
<option th:selected="${player.playerPosition}" th:text="${player.playerPosition}"></option>
<option value="GK">Goalkeeper</option>
<option value="RWB">Right Wingback</option>
<option value="RCB">Right Centreback</option>
(...)
</select>
as per kindly advice:
ok, tried and found such request with thymeleaf conditional:
<option th:if="${player.playerPosition!=null}" th:selected="${player.playerPosition}" th:text="${player.playerPosition}"></option>
it's not excactly how I expected but gives some solution –

Select2 getting multiple selections after form POST

I have this select2 multi-selection dropdown that works fine on the client side but only posts the last selection users make:
<select class="searchable-dropdown form-control form-control-md" name="payment_methods" id="payment-methods-send" multiple="multiple">
<%= options_for_select( (::Transaction::SEND_METHODS).collect{ |m| [t(m[:name]), m[:name].parameterize ]}, selected: params[:payment_method] ) %>
</select>
It generates the following markup:
<select class="searchable-dropdown form-control form-control-md" name="payment_methods" id="payment-methods-receive" multiple="multiple">
<option value="coupons">Coupons</option>
<option value="paypal">Paypal</option>
<option value="skrill">Skrill</option>
<option value="revolut">Revolut</option>
<option value="zelle">Zelle</option>
<option value="transferwise">Transferwise</option>
<option value="swift-bank-transfer">SWIFT bank transfer</option>
<option value="european-bank-transfer">European bank transfer</option>
<option value="us-bank-transfer">US bank transfer</option>
<option value="uk-bank-transfer">UK bank transfer</option>
<option value="check">Check</option>
</select>
I've used this to initialize the control:
$( ".searchable-dropdown" ).select2({ theme: "bootstrap" });
After making several selections and sending the form, I am getting this within params:
"payment_methods":"paypal"
Paypal was indeed selected (last) but so were a bunch of other selections.
Was it not supposed to send them comma-separated or something? Am I doing something wrong?
Nevermind, looks like I wasn't asking Google the right question...
Multiple select box is not working in rails
You need to make sure that you are sending an array of answers by
changing the name to payment_methods[]

Sending select back to controller

I am trying to send a listbox back to my controller from my view. I dynamically add items to it with a text box and button, and I want to be able to send all of these items back to my view in some kind of array. How would I go about doing this?
I had the following modelcode:
[HttpPost]
public ActionResult BasicIdentificationIndex(MyObject returndata, List<int> ints)
And then some input boxes:
<input type="text" name="ints" value="1" />
<input type="text" name="ints" value="4" />
<input type="text" name="ints" value="2" />
<input type="text" name="ints" value="8" />
This code works and is returned to my controller(not null).
EDIT:
My issue is that I cannot get a select list to post back to my controller. I would like to send the following back to my controller:
<select name="selectfrom" id="select-from" multiple size="5">
<option value="String1">Item 1</option>
<option value="String2">Item 2</option>
<option value="String3">Item 3</option>
<option value="String4">Item 4</option>
</select>
How would I go about doing this so that I can send a list of all the options( String1,String2,etc.) back to my controller? I have tried the following:
Controller:
public ActionResult BasicIdentificationIndex(BasicIdentificationModel returndata,ICollection<String> AerialItems)
Model:
public String AerialItems { get; set; }
View:
<select name="AerialItems" id="select-to" multiple size="5">
<option value="5">Item 5</option>
<option value="6">Item 6</option>
<option value="7">Item 7</option>
</select>
But The item returned back to the controller is always null.
You should be able to just model bind back to a collection of ints...
I'm somewhat confused because this seemed to be copied from Haack's blog post on the subject... What you have listed should work, but if it's not could you include the rest of your code?
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
Figured it out. I need to use Javascript to select all the items in the list. This will post them all back in the collection.

Submitting form elements with the same name

I have a form which allows the user to create extra "rows" using JQuery (using .clone) so that they can decide how many of the same information they need to submit. My issue is that I cannot work out how to access these form items within my controller.
the form that is being submitted may look like this
<input type="text" name="Amount" id="Amount">
<select name="Item">
<option value="1">Item 1"</option>
<option value="2">Item 2"</option>
<option value="3">Item 3"</option>
</select>
<input type="text" name="Amount" id="Amount">
<select name="Item">
<option value="1">Item 1"</option>
<option value="2">Item 2"</option>
<option value="3">Item 3"</option>
</select>
<input type="text" name="Amount" id="Amount">
<select name="Item">
<option value="1">Item 1"</option>
<option value="2">Item 2"</option>
<option value="3">Item 3"</option>
</select>
Basically, the block between input and the select could be repeated an infinite number of times. When I submit to the controller I am then using FormCollection form to access the form elements. from there I am unsure how I can access the items that have been submitted. I thought of using a for loop and then accessing them via something like form["Amount"][i] but obviously that is not going to work.
Am I going about this the right way and if so, does anyone have any suggestions about how this might work?
Thanks in advance.
Old question, but still...
You can get the posted values as an array by calling Request.Form.GetValues, or Request.QueryString.GetValues. For example:
string[] amounts = Request.Form.GetValues("Amount");
And the amounts array will contain the correct values, so you can post values containing comas, dots, whatever, and don't worry about splitting/parsing it.
Of course if you are running MVC, use the modelbinder to do it. But you can use this if you are using webforms, a generic handler, etc...
Check out Model Binding To A List. Your Action method should be:
public ActionResult MyAction(string[] Amount, int[] Item){
// ...
}
However this will make you need to "link" the items. Alternatively create a "Item" class:
public class Item {
public string Amount { get; set; }
public int Item { get; set; }
}
And
public ActionResult MyAction(IList<Item> items){
// ...
}
And your markup should be:
<input type="hidden" name="items.Index" value="0" />
<input type="text" name="items[0].Amount" id="items[0].Amount">
<select name="items[0].Item">
<option value="1">Item 1"</option>
<option value="2">Item 2"</option>
<option value="3">Item 3"</option>
</select>
<input type="hidden" name="items.Index" value="1" />
<input type="text" name="items[1].Amount" id="items[1].Amount">
<select name="items[1].Item">
<option value="1">Item 1"</option>
<option value="2">Item 2"</option>
<option value="3">Item 3"</option>
</select>
Etc...
I believe if you have multiple fields named Amount the values will be comma delimited.
To access each one just try:
string[] amounts = Request.Form["Amount"].Split(new char[] { ',' });
Keep in mind though, the inputs are not cleaned on submission so if someone enters a comma into the text box it's going to cause issues.
Hence I'd recommend numbering them.
I ended up realising that (blush) the mechanism which JQuery uses to find the string within the cloned row (to replace) is basically regex. Thus I just needed to escape the square brackets and period. Once I did this I was able use JQuery to create form as Phil Haack's blog suggested.
Onto my next issue...!
I would number them Amount1, Amount2, Amount3 etc.
You can change the id and name attribute of the input to something like this "Amount[1]","Amount[2]","Amount[3]" (yes, the id and name attribute can contain the special chars "[" or "]"). Then in the controller, write a http request parameter parser to get back the Amounts as collections.

Resources