I have a list of parameters like this:
<input class="form-control" name="analysis[strengths][0]" id="swot_analysis_strengths_0" type="text">
<input class="form-control" name="analysis[strengths][1]" id="swot_analysis_strengths_1" type="text">
...
etc
Then there's also
<input class="form-control" name="analysis[weaknesses][x]" id="swot_analysis_strengths_2" type="text">
<input class="form-control" name="analysis[opportunities][x]" id="swot_analysis_strengths_2" type="text">
<input class="form-control" name="analysis[threats][x]" id="swot_analysis_strengths_2" type="text">
In my controller I have
params.require(:swot_analysis).permit(:strengths, :weaknesses, :opportunities, :threats)
That doesn't work. The only way I've got it to work so fat is by doing this
sanitized_params = params.require(:swot_analysis).permit(:strengths =>['0','1'], :weaknesses =>['0','1'], :opportunities =>['0','1'], :threats =>['0','1'])
However the number of members for each array will vary, users will be able to add and remove members as they please. So I need a method to simply permit any sub-param of the original for parameters.
Would be nice to allow it only if it's a number, but not really a priority right now
This should take care of the member array lengths:
params.require(:swot_analysis).permit(:strengths =>[], :weaknesses =>[], :opportunities =>[], :threats =>[])
http://api.rubyonrails.org/classes/ActionController/Parameters.html
Related
I need to replace the following helper with its corresponding HTML in a view:
#Html.HelperTextBoxFor(model => model.Length, new { #ng_change = "changeArea()" })
I came up with this:
<input type="text" data-ng-model="MyViewModel.Length" class="form-control" />
But I cannot find where to add the new { #ng_change = "changeArea()"}
Can anyone help me please?
If this #ng_change="..." is an Angular directive, this would look like this in an input tag:
<input type="text" data-ng-model="MyViewModel.Length" class="form-control" ng-change="changeArea()"/>
reference: https://docs.angularjs.org/api/ng/directive/ngChange
You need to get back to the basics here, not sure why you can't figure it out.
http://www.w3schools.com/jsref/event_onchange.asp
<input type="text" data-ng-model="MyViewModel.Length" class="form-control" onchange="changeArea();" />
I have a model containing some complex types including nested lists. So I cannot simply use the model.
My initial thought is using knockoutjs to take care of the user interactions (add/delete list items etc.), and post knockoutjs view model via ajax.
But after some googling, I found I could give meaningful name attributes in my form elements and do regular form submit to post my form model like this.
<input checked="checked" data-val="true" data-val-required="The Boolean field is required." name="Questions[0].SubQuestions[0].OptionAnswers[0]" type="checkbox" value="true">
Of course I still need some javascript for list manipulations and stuff.
Which approach is more preferred?
EDIT:
Sorry for the indexing issue. I was aware it should be sequential and start from 0. I just took a random element from my generated html. The indexing is not really my issue. I just would like to know which approach is more preferred.
I start liking the regular form submission way as it takes advantage of the validation feature of DataAnnotations and Html.ValidationSummary. What's the advantages for ajax post?
You are very close to understand the concept how asp.net mvc model binder works out of the box.
This is the link to an article from where I learnt how to achieve similar requirement.
The way that mvc model binder reads in the properties is by looking for parameterName[index].PropertyName. The index must be zero-based and unbroken. Say suppose, if you have your html like below which is a list for example and it can be your Questions list which is a complex type:
<input type="text" name="people[0].FirstName" value="George" />
<input type="text" name="people[0].LastName" value="Washington" />
<input type="text" name="people[1].FirstName" value="Abraham" />
<input type="text" name="people[1].LastName" value="Lincoln" />
<input type="text" name="people[3].FirstName" value="Thomas" />
<input type="text" name="people[3].LastName" value="Jefferson" />
When you submit the above values to asp.net mvc controller, the above value turns into:
people%5B0%5D.FirstName=George&people%5B0%5D.LastName=Washington&people%5B1%5D.FirstName=Abraham&people%5B1%5D.LastName=Lincoln&people%5B3%5D.FirstName=Thomas&people%5B3%5D.LastName=Jefferson
The mvc model binder then read the above data as:
people[0].FirstName = "George"
people[0].LastName = "Washington"
people[1].FirstName = "Abraham"
people[1].LastName = "Lincoln"
people[3].FirstName = "Thomas"
people[3].LastName = "Jefferson"
So, as you can see we have list items for index 0, 1 and then 3. It is broken! This results in mvc model binder only translating this data to a list of type people for only two items i.e. index 0 and 1. It excludes 3 as there was no data at index 2.
this answer has information from the same article. If you understand this, you will understand the role of name attributes and you will appreciate how easy it is to follow the rules and mvc binder will understand all your posted data.
If you want to make sure that mvc binder constructs a list from the posted data even if any index is missing then refer Eric's answer
Yoda's answer is very very good. However there is a known way to have a list of Non-Sequential Indices for postback as Phil Haacked describes in Model Binding To A List (Non-Sequential Indices heading)
<input type="hidden" name="products.Index" value="0" />
<input type="text" name="products[0].Name" value="Beer" />
<input type="text" name="products[0].Price" value="7.32" />
<input type="hidden" name="products.Index" value="1" />
<input type="text" name="products[1].Name" value="Chips" />
<input type="text" name="products[1].Price" value="2.23" />
<input type="hidden" name="products.Index" value="3" />
<input type="text" name="products[3].Name" value="Salsa" />
<input type="text" name="products[3].Price" value="1.23" />
I have the following Domains:
class Attribute {
static hasMany = [attributeParameters: AttributeParameter]
}
class AttributeParameter {
String value
Integer sequenceNo
static belongsTo = [attribute: Attribute]
}
I have a form where I want to display all the existing AttributeParameters for an Attribute and allow the user to populate their values and click Save. On Save, each AttributeParameter (which already has an ID) needs to be updated.
I'm currently drawing a blank on how I need to create the HTML for this to work. I've tried this:
Code simplified to clarity:
<form>
<input type="hidden" name="attributeParameters[0].id" value="1" />
<input type="text" name="attributeParameters[0].value" value="1234567" />
<input type="hidden" name="attributeParameters[1].id" value="2" />
<input type="text" name="attributeParameters[1].value" value="name" />
</form>
def save() {
def attribute = Attribute.get(params.id)
attribute.properties = params
}
and it populates the collection correctly, but it doesn't work because the AttributeParameter isn't being fetched before the save, so it is failing with an error:
A collection with cascade="all-delete-orphan" was no longer referenced
by the owning entity instance: com.foo.Attribute.attributeParameters
UPDATE:
I modified the HTML to the following:
<form>
<input type="hidden" name="attributeParameters.id" value="1" />
<input type="text" name="attributeParameters.value" value="1234567" />
<input type="hidden" name="attributeParameters.id" value="2" />
<input type="text" name="attributeParameters.value" value="name" />
</form>
And the controller:
params.list('attributeParameters').each {
def ap = AttributeParameter.get(it.id)
ap.value = it.value
ap.save()
}
This works. My only concern is the order in which the parameters come in. If they always come into the params object in the same order they show up on the form, then I should be ok. but if they ever come in differently, I could be modifying the value of the wrong AttributeParameter.
So still looking for a better way or some sort of verification that they params will always be first in-first out.
UPDATE 2:
I ran across this post and it is what I want but I cannot change Attribute.attributeParameters into a List. They need to stay as a Set.
Could you do something like this:
<form>
<input type="text" name="attributeParameter.1" value="1234567" />
<input type="text" name="attributeParameter.2" value="name" />
</form>
Where you create the names and values dynamically from each AttributeParameter:
<g:textField name="attributeParameter.${attributeParameterInstance.id}" value="${attributeParameterInstance.value}" />
And then in your controller
params.attributeParameter.each {id, val->
def ap = AttributeParameter.get(id)
ap.value = val
ap.save()
}
That way you have the actual id of each parameter directly and it wouldn't matter which order they were processed.
Folks,
I am using watir-webdriver, I have a piece in my HTML DOM which gets generated on the fly when I enter some credentials, this piece has a bunch of checkboxes, the number of checkboxes vary, I have to select one checkbox, below is an example of this, here I want to select the second checkbox(the one that has value "BS" for the input type hidden but the value for input type checkbox is same for all):
<li class="dir">
<input type="checkbox" value="1" onclick="$(this).next('.should_destroy').value = (this.checked?0:1)" name="should_not_destroy">
<input class="should_destroy" type="hidden" value="1" name="import[dir_attributes][][should_destroy]">
<input type="hidden" value="" name="import[dir_attributes][][id]">
<input type="hidden" value="Automation" name="import[dir_attributes][][path]">
<span class="dir_mode">Include</span>
Automation
</li>
<li class="dir">
<input type="checkbox" value="1" onclick="$(this).next('.should_destroy').value = (this.checked?0:1)" name="should_not_destroy">
<input class="should_destroy" type="hidden" value="1" name="import[dir_attributes][][should_destroy]">
<input type="hidden" value="" name="import[dir_attributes][][id]">
<input type="hidden" value="BS" name="import[dir_attributes][][path]">
<span class="dir_mode">Include</span>
BS
</li>
I may be able to do this with XPATH, but wanted to try a non XPATH solution. The input type hidden has the appropriate value that I need, for example above the second checkbox has value "BS" for input type hidden. I tried to use the hidden method like this:
h = ##browser.hidden(:value, "BS")
h.select
But I dont know what to do after this. I am trying to select the checkbox based on the value of the hidden element. Any feedback is much appreciated.
I would suggest using the visible elements instead. I think it makes it easier to read the test and seems more stable.
Try:
##browser.li(:class => 'dir', :text => /BS/).checkbox.set
Here we go, I think this will do it
Since you have to select the checkbox based on the hidden, you're going to have to go up a level to the containing li, then drill down to the checkbox
#browser.hidden(value: 'BS').parent.checkboxes.first.set
This is a follow-up to this question where's the appropriate place to handle writing the current_user.id to an object I have the following model. An item which has_many assets. I'm am using accepts_nested_attributes_for :assets in the item.
I'd like to assign the current_user.id value to each asset. Normally I just do #item.update_attributes(params[:item]) to save it. Is there a simple one line way of setting the user_id for each asset in this scenario?
Looking in dev log, I see the value here:
item[assets_attributes][10][asset]
Should I just iterate through all of these and set a user_id value?
thx
here's some more of the html (items -> menu_item; had left out above to simplify). The proposed controller sol'n below does not seem to work. I'm fine with doing at the level of controller. Any help appreciated.
<div class='image-row'>
<input id="menu_item_assets_attributes_18_asset" name="menu_item[assets_attributes][18][asset]" type="file" />
<input id="menu_item_assets_attributes_18_description" name="menu_item[assets_attributes][18][description]" size="30" type="text" />
</div>
<div class='image-row'>
<input id="menu_item_assets_attributes_19_asset" name="menu_item[assets_attributes][19][asset]" type="file" />
<input id="menu_item_assets_attributes_19_description" name="menu_item[assets_attributes][19][description]" size="30" type="text" />
</div>
<div class='image-row'>
<img alt="D5cc413a1748fb43b0baa2e32e29b10ac2efda10_huntbch_thumb" src="/images/371/d5cc413a1748fb43b0baa2e32e29b10ac2efda10_huntbch_thumb.jpg?1329917713" />
<div class='img-row-description'>
<label for="menu_item_assets_attributes_20_description">Description</label>
<input id="menu_item_assets_attributes_20_description" name="menu_item[assets_attributes][20][description]" size="60" type="text" value="here is my comment" />
<label for="menu_item_assets_attributes_20_destroy">Destroy</label>
<input name="menu_item[assets_attributes][20][_destroy]" type="hidden" value="0" /><input id="menu_item_assets_attributes_20__destroy" name="menu_item[assets_attributes][20][_destroy]" type="checkbox" value="1" />
</div>
This answer is probably a little bit muddier than your previous one.
If each asset must have an item, then it might be more sensible to remove the idea of an owning user from an asset entirely: you can always find the owning user by querying the attached item, something like #asset.item.user. However, if users can own assets independently of items, I don't think this will work for you.
If assets are always created in a nested manner for items, a before_create for the asset could assign the value you want. Something like this in asset.rb:
before_create :assign_user
def assign_user
self.user = self.item.user if self.item && self.item.user
end
Finally, if you just want to do it in the controller, Wolfgang's answer is really good and will add the user_id to each asset_attributes.
How about iterating over the params array and setting the value like so:
params[:item][:assets_attributes].map! do |asset_params|
asset_params[:user_id] = current_user.id
end
Now you can use update_attributes( params[:item] ) as before.