I'm using Laravel 5's Form Request Validation feature to validate a form input.
In my form, I have 2 fields num_adults and num_children.
I need to ensure that the sum of both fields do not exceed a certain value.
What I've tried is in the rules() function of my validation file, I used merge() to artificially add a new input value that is the sum of both num_adults and num_children.
$this->merge([
'max_persons' => $this->input('num_adults') + $this->input('num_children')
]);
And then in the rules array returned,
$rules = [
'num_adults' => 'integer|max:2',
'num_children' => 'integer|max:1',
'max_persons' => 'integer|max:2',
];
The validation works fine for num_adults and num_children. But max_persons seems to be ignored.
I might skip the array merge and have my rules like:
$rules = [
'num_adults' => 'integer|max:'.(2-$this->get('num_children', 0)) ,
'num_children' => 'integer|max:'.(2-$this->get('num_adults', 0))
];
2 being the maximum permitted value.
On the other hand, the approach that you've started gives you a little more flexibility on the error messages.
The validator already has the values before you update the array, so it doesn't know about your addition. You could add a validator method to your request object to merge in your values a little earlier in the process.
public function validator(Factory $factory)
{
$this->merge([
'max_persons' => $this->input('num_adults') + $this->input('num_children')
]);
return $factory->make(
$this->all(),
$this->rules(),
$this->messages()
);
}
Related
I'm trying to search Umbraco (v10) tags, which are stored as an array. Regardless of whether they are stored in CSV or JSON, I can't force an exact match.
For example, one article has tags containing "foo bar", while a second article has tags containing "foo".
If I use Lucene to search for foo, I get both articles returned. I do not want to match "foo bar".
This is my code:
IBooleanOperation query = _externalIndex.Searcher
.CreateQuery("content", BooleanOperation.And)
.NodeTypeAlias(modelTypeAlias)
.And()
//.Field("tags", tag);
.NativeQuery($"tags:\"{tag}\"");
I have tried using NativeQuery, wrapping my tag in quotes, using regex to match start/end of the string, using parenthesis to indicate a set of matches.
I cannot identify a way to isolate an exact match.
While your question is slightly different the this one, the answer is basically the same.
If you want the index to be based on the whole field rather then the individual words then you need to make sure the field is indexed as a StringField rather then a TextField.
String fields are not tokenized.
RonC's answer pointed me in the right direction, but it was more complicated than that.
I needed to split the JSON array of tags into individual elements, using the TransformingIndexValues event handler, and store them in a new field tagsSplit:
private void TransformTagsValues(object? sender, IndexingItemEventArgs e)
{
if (e.ValueSet.Category != "content")
{
return;
}
Dictionary<string, List<object>> updatedValues = e.ValueSet.Values.ToDictionary(x => x.Key, x => x.Value.ToList());
if (!updatedValues.ContainsKey("tags"))
{
return;
}
JArray tagsArray = JArray.Parse(updatedValues["tags"].Single().ToString()!);
updatedValues["tagsSplit"] = tagsArray.Select(token => (object)token.Value<string>()!).ToList();
e.SetValues(updatedValues.ToDictionary(x => x.Key, x => (IEnumerable<object>)x.Value));
}
Then I needed to configure the indexer to treat the field values as Raw (which internally uses StringField):
public void Configure(string name, LuceneDirectoryIndexOptions options)
{
if (name.Equals(UmbracoIndexes.ExternalIndexName))
{
options.FieldDefinitions.AddOrUpdate(new FieldDefinition("tagsSplit", FieldDefinitionTypes.Raw));
}
}
Now finally if I query using field:
IBooleanOperation query = _externalIndex.Searcher
.CreateQuery("content", BooleanOperation.And)
.NodeTypeAlias(modelTypeAlias)
.And()
.Field("tagsSplit", tag);
It gives me an exact match.
It is also case-sensitive, but since I'm searching by existing tags and not free-text, that is fine for my use-case.
I am new to Rails, and working with some JSON, and not sure how to get to the data as the examples below:
1) If i were to use JSON.parse(response)['Response']['test']['data']['123456'], i will need to parse another response for 123457, is there a better way to loop through all the objects in data?
2) base on the membershipId, identify the top level object, ie data.
"test": {
"data": {
"123456": {
"membershipId": "321321312",
"membershipType": a,
},
"123457": {
"membershipId": "321321312",
"membershipType": a,
},
}
JSON.parse(response)['Response']['test']['data'].each do |key, object|
puts key
puts object['membershipID']
...
end
To select the data record associated with a particular membership
match_membership = '321321312'
member = JSON.parse(response)['Response']['test']['data'].select |_key, object|
object['membershipID'] == match_membership
end
puts member.key
=> 123456
For 1:
Assumption:
By you saying "need to parse another response", you were doing something like below:
# bad code: because you are parsing `response` multiple times
JSON.parse(response)['Response']['test']['data']['123456']
JSON.parse(response)['Response']['test']['data']['123457']
then simply:
Solution 1:
If you are gonna be accessing 2+ level deep hash values for just maybe 2 or 3 times,
response_hash = JSON.parse(response)
response_hash['Response']['test']['data']['123456']
response_hash['Response']['test']['data']['123457']
Solution 2:
If you are gonna be accessing 2+ level deep hash values for loooooots of times,
response_hash = JSON.parse(response)
response_hash_response_test_data = response_hash['Response']['test']['data']
response_hash_response_test_data['123456']
response_hash_response_test_data['123457']
response_hash_response_test_data['123458']
response_hash_response_test_data['123459']
response_hash_response_test_data['123460']
# ...
Solution 2 is better than Solution 1 because it saves repetitive method calls for Hash#[] which is the "getter" method each time you do like ...['test'] then ['data'] then ['123456'], and so is better-off doing Solution 2 which you store the nested-level of the hash into a variable (this does not duplicate the values in-memory!). Plus it's more readable this way.
I'm studying DynamoDB using rails and I got a doubt.
I not be able to find a solution on web, so If you can solve it I'll thank.
The doubt is how can I find values into array saved on a table, for example:
I have a lot of data in my_table where there are fields called "numbers" that are arrays like:
[1,2,3,4]
[3,4,5,6]
[1,3,4,7]
[4,7,8,10]
[8,9,12,14]
[12,14,16,20]
So, I want select all entries that contains numbers 1,3,4. In this case four results.
So, my code is
result = dynamodb.scan({
table_name: "my_table",
select: "ALL_ATTRIBUTES",
attributes_to_get: ["numbers"],
scan_filter: {
"numbers" => {
attribute_value_list: [1,3,4],
comparison_operator: "CONTAINS"
}
}
})
But I get this error: One or more parameter values were invalid: Invalid number of argument(s) for the CONTAINS ComparisonOperator
How can I do this action using dynamo DB?
Thanks a lot
Try this and let me know if it works, I know from experience that DynamoDB is very painful to filter.
result = dynamodb.scan(
table_name: 'my_table',
expression_attribute_values: {
':one' => 1,
':two' => 2,
':three' => 3,
':four' => 4
},
filter_expression: 'contains(numbers, :one) OR contains(numbers, :two) OR contains(numbers, :three) OR contains(numbers, :four)'
)
I can't think of anything simpler currently, the method you linked is marked as deprecated, instead you should use expression_attribute_values and filter_expression.
Basically I want to update each table column for a Model in Rails 5.
str = "abc---def"
str.split('---').map do |a|
Foo.where(product_id:1).update_all(bar: a)
end
Old object would be like:
[
[0] { product_id: 1,
...,
bar: "xxx",
...
},
[1] { product_id: 1,
...,
bar: "xxx",
...
}
]
New should be like:
[
[0] { product_id: 1,
...,
bar: "abc",
...
},
[1] { product_id: 1,
...,
bar: "def",
...
}
]
But what I got is bar: "def" for each. Is there a clean method in rails to achieve what I want? update_attributes gives an error.
Is the title name correct?
First of all let's get started from some basics.
You want to update multiple rows and want to set different value for each row. So it cannot be done in single query like you are doing. So you need to loop through the Foo objects and set each one separately.
So let's assume
str = "abc---def---ghi---jkl"
tokens = str.split('---')
foos_to_update = Foo.where(product_id: 1) #Let's assume it will return 4 or lesser records. (otherwise you need to tell what do you wanna do if it returns more then `tokens`)
foos_to_update.each_with_index {|foo,i| foo.update(bar: tokens[i])}
The last line is looping through returned objects and setting the bar value for each object.
First of all, using Foo.where(id:1).update_all to update a single record may work, but is non-idiomatic. It's better to use Foo.find_by(id: 1).update. For getting single records, I prefer to use find_by instead of find because it returns nil instead of raising NotFound errors, but that's a personal preference.
Second, the way you're using update_all(bar: a) is giving you unexpected results. In a map block, the returned value becomes part of the resulting array. update_all doesn't return the record which were changed. It returns an integer showing the count of records which were changed. Similarly, update doesn't return the record. It returns true or false` depending on if the validations passed.
Tying together these concepts, the following code can be written:
str = "abc---def"
str.split('---').map do |a|
foo = Foo.find_by(id:1)
foo&.update(bar: a)
foo
end
# note that you could instead write `foo.update(bar: a)` if you
# don't want to use the safe navigation operator
Or another way to write it which does the same thing:
str = "abc---def"
str.split('---').map do |a|
Foo.find_by(id:1)&.tap { |foo| foo.update(bar: a) }
end
Note that in these examples I'm using the safe navigation operator which is in Ruby versions newer than 2.3. It helps prevent NoMethodError on nil objects, but isn't really necessary.
I have an MVC 3 project in Visual Studio c#. I have a LINQ to SQL query which works fine and by following an example listed elsewhere on stackoverflow:
Comparing two lists using linq to sql
I have been able to successfully reduce my results where my two nested collections match. This is the bit of code that did the trick (example from the link above):
var anyDesiredSkills = canidateSkills.Any( c => desiredSkills.Select( ds => ds.SkillId ).Contains( c.SkillId ) );
I've adapted this successfully, but now I need to be able to filter records using more than one condition. I was wondering if anyone would be able to adapt the above to show how you could include more than one condition?
To give you some background on what my goal is:
A search page where you can select any number of contacts
Each contact added to the search criteria may/may not have a 'role' assigned. If a role is present this should be factored in to the query.
Results returned based on this dynamic criteria.
Thanks in advance for any and all help :O)
It sounds like you're looking for something like:
var desiredSkillIds = desiredSkills.Select(_=>_.SkillId).ToList();
var matchingContacts =
from contact in Contacts
where contact.Role == null || desiredRoles.Contains(contact.Role)
where contact.Skills.Any(cs=> desiredSkillIds.Contains(cs.SkillId))
select contact;
Or in method-based syntax:
var matchingContacts = Contacts
.Where(contact => contact.Role == null || desiredRoles.Contains(contactRole))
.Where(contact => contact.Skills.Any(cs => desiredSkillIds.Contains(cs.SkillId)));
Here's the final code I used:
servicelist = servicelist.Where(
d => d.ContactSelection.Any(
h => model.ContactFilter.Select(ds => ds.StaffNumber).Contains(h.StaffNumber)
&&
model.ContactFilter.Select(ds => ds.ContactRole).Contains(h.ContactRole) || model.ContactFilter.Select(ds => ds.StaffNumber).Contains(h.StaffNumber) && model.ContactFilter.Select(ds => ds.ContactRole).Contains("0"))
);
Note that the last filter .Contains("0) is the value of '-- select role --' which is an option injected in to the drop down. Hope this helps anyone else!