Ruby put in order columns when creating CSV document from Mongoid - ruby

I need to create CSV document from database. So I want to organise columns in particular order and I have template of this order and this template stored as array of headers
header = ["header1", "header2", "header3", "header4", "header5"]
record = [{"header4" =>"value4"}, {"header3" =>"value3"}, {"header5"=>"value5"}, {"header1"=>"value1"}, {"header2"=>"value2"}]
I need to get array like tis
record = [{"header1" =>"value1"}, {"header2" =>"value2"}, {"header3"=>"value3"}, {"header4"=>"value4"}, {"header5"=>"value5"}]
but when I doing
csv<< mymodel.attributes.values.sort_by! { |h| header.index(h.keys[0])
It does not work

When you call mymodel.attributes, you get a Hash back which maps attributes names (as strings) to their values. If your attribute names are header1 through header5 then mymodel.attributes will be something like this:
{
'header1' => 'value1',
'header2' => 'value2',
'header3' => 'value3',
'header4' => 'value4',
'header5' => 'value5'
}
Of course, the order depends on how things come out of MongoDB. The easiest way to extract a bunch of values from a Hash in a specified order is to use values_at:
mymodel.attributes.values_at(*header)

Related

Require a field if the value exists in another field, which is an array

Say a model has a status property, that holds an array of strings. If this array contains a string name "Other", the status_other field should be required. I can achieve this with the following rules:
'status' => 'nullable|array',
'status_other' => Rule::requiredIf(in_array('Other', $this->model->status))
Is there a way to write the status_other rule as a string? I tried:
'status_other' => 'required_if:status,in:Other',
and
'status_other' => 'required_if:status,Other',
Both that did not work.
You can compare it by using '==' to match the string in the array.
'status_other' => 'required_if:status,==,Other',

Most efficient way to extract an item from a Ruby array of hashes

I have some large Ruby structures that I need to quickly extract data from. I have no control over the format of the data, although I'm open to transforming it under certain circumstances. What is the most efficient way to extract a single item from the following hash, when using the displayName as the 'key'.
[
{'displayName'=>'Some Key 1', 'values'=>[1,2,3]},
{'displayName'=>'Some Key 2', 'values'=>["Some text"]},
{'displayName'=>'Some Key 3', 'values'=>["Different text","More text"]},
{'displayName'=>'Some Key 4', 'values'=>[2012-12-12]}
]
Each hash has other keys in it that I've removed to assist understanding.
The challenge is that in certain circumstances, the displayName field will need to be matched on a prefix sub-string. Does anybody have any practical experience knowing when to use .each and match manually, or .select to get the common case exact matches and fallback for the prefixes afterwards. Or is there some common trick I'm missing.
If you're doing this once, you'll probably just have to iterate over the set and find what you need:
row = data.find do |row|
row['displayName'] == name
end
row && row['values']
If you're doing it more than once, you should probably make an indexed structure out of it with a simple transform to create a temporary derivative structure:
hashed = Hash[
data.collect do |row|
[ row['displayName'], row['values'] ]
end
]
hashed[name]
You can use simple select thought it may no be as fast as it could with large sized arrays:
data = [
{'displayName'=>'Some Key 1', 'values'=>[1,2,3]},
{'displayName'=>'Some Key 2', 'values'=>["Some text"]},
{'displayName'=>'Some Key 3', 'values'=>["Different text","More text"]},
{'displayName'=>'Some Key 4', 'values'=>[2012-12-12]}
]
data.select { |e| e['displayName'] == 'Some Key 2' }.first
You can group_by the desired key instead, wich will make access faster
hashed_data = data.group_by { |e| e['displayName'] }
hashed_data['Some Key 4']
=> [{"displayName"=>"Some Key 4", "values"=>[1988]}]

Set array elements (string) as variable name in Ruby

I have the following array, that I use to later write the header on an Excel file.
fields = ["fileName", "type", "id"]
And then I have the following code that reads values from an XML:
filename = xml.xpath('//path/filename').text
type = xml.xpath('//path/type').text
id = xml.xpath('//path/id').text
The I iterate the initial array (fields) in order to set the Excel cells to the values extracted in the previous step:
row = 2
c = 1
fields.each do |content|
ws.Cells(row,c).Value = content
c = c + 1
I'm trying to have the array's (fields) contents to variable names instead of strings in order to be able to reuse the head fields.
Can anyone recommend a way of making it possible?
This sounds like you need to use a Hash to associate field names to the values you extracted:
fields = {
"fileName" => xml.xpath('//path/filename').text,
"type" => xml.xpath('//path/type').text,
"id" => xml.xpath('//path/id').text
}
row=2
c=1
fields.each do |key,value|
ws.Cells(row,c).Value = value
c=c+1
end

CodeIgniter: Using array within array

I am following nettut+ tutorial for pagination and to store POST inputs as querystrings in db. So far, everything works fine until, suppose if I get an array as POST input, i am unable to loop through it and get all the array values and to store into query_array (i.e., store array within array).
The snippets below:
$query_array = array(
'gender' => $this->input->post('gender'),
'minage' => $this->input->post('minage'),
'maxage' => $this->input->post('maxage'),
'Citizenship' => $this->input->post('citizenship'), // checkboxes with name citizenship[]
);
This returns only last stored array value in Citizenship.
The output array:
Array ( [gender] => 1 [minage] => 18 [maxage] => 24 [Citizenship] => 2 )
makes the query string as:
&gender=1&minage=18&maxage=24&Citizenship=2
But, my requirement is to get all the values of 'Citizenship' array instead of last stored value.
The output required to make query string:
Array ( [gender] => 1 [minage] => 18 [maxage] => 24 [Citizenship] => 2 [Citizenship] => 4 [Citizenship] => 6 )
The query string :
&gender=1&minage=18&maxage=24&Citizenship[]=2&Citizenship[]=4&Citizenship[]=6
Any help appreciated..
Thanks.
Doesn't look like code ignighter supports un-named multidimensional arrays as input without a bit of hacking.
If you can access raw $_POST data try replacing
$this->input->post('citizenship')
with
array_map('intval',$_POST['citizenship'])
Alternativly add keys to your post data:
&gender=1&minage=18&maxage=24&Citizenship[0]=2&Citizenship[1]=4&Citizenship[2]=6
I fixed it myself. I just looped through the POST array and got the individual array key & pair values.
foreach($_POST['Citizenship'] as $k => $v) {
$Citizenship[$v] = $v;
}
Hope this helps someone who face similar problem.

Selecting on a many table using Linq

I have a recipe table that has a related ingredients table
on one to many basis.
How do I select using Linq ingredients
that have a ingredientName column and it should contain
a specified word.
This is what I tried.
IQueryable<OurRecipes.Domain.Linq2Sql.Recipe> recipes = _dbctx.Recipes.AsQueryable();
foreach (string word in searchdata.Keywords)
{
recipes = recipes.Where(r => r.RecipeTitle.Contains(word));
recipes = recipes.Where(r => r.Ingredients.Where(i => i.IngredientName.Contains(word)));
}
I get cannot convert type 'etc' to bool error.
Any ideas
Malcolm
The error lies here:
recipes = recipes.Where(r => r.Ingredients.Where(i => i.IngredientName.Contains(word)));
The condition inside Where must return a boolean, in this case, the r.Ingredients.Where(i => i.IngredientName.Contains(word)) will not return a boolean, and hence the error.
This is how you can fix the problem:
recipes = recipes.Where(i => i.Ingredients.Any(row=>row.IngredientName.Contains(word)));
r.Ingredients.Where(i => i.IngredientName.Contains(word)));
replace with
r.Ingredients.Any(i => i.IngredientName.Contains(word)));
Btw, I like SQL like syntax more as it more netural. The same:
from r in _dbctx.Recipes
where r.Ingredients.Any(i => i.IngredientName.Contains(word)));
select r;
This will select all recipies that has ingredients with name contains word.

Resources