How to check existance and nil in single line for variable in ruby on rails - ruby-on-rails-4

def import_update
require 'csv'
file = params[:file]
CSV.foreach(file.path, headers: true) do |row|
#prod = Spree::Product.find(row["id"])
#var = Spree::Variant.find_by(product_id: #prod.id)
Spree::Product.where(:id => row["id"]).update_all(:name => row["name"] if !row[name].nil?.present?, :meta_description => row["meta_description"], :shipping_category_id => row["shipping_category_id"], :description => row["description"], :meta_keywords => row["meta_keywords"], :tax_category_id => row["tax_category_id"], :available_on => row["available_on"], :deleted_at => row["deleted_at"], :promotionable => row["promotionable"], :meta_title => row["meta_title"], :featured => row["featured"], :supplier_id => row["supplier_id"])
end
end
I want check that row is present or not. if it is present then it updated when it is not null and condition is in single line because I want to apply this for all variable in updation statement.I wrote code above but showing error.

Try this:
params = ["name","meta_description","shipping_category_id","description","meta_keywords","tax_category_id","available_on","deleted_at","promotionable","meta_title","featured","supplier_id"
hash = {}
params.each do |param|
if row[param]
hash[param] = row[param]
end
end
Spree::Product.where(:id => row["id"]).update_attributes(hash)
This will let you keep your code dry.
EDIT:
What are these lines supposed to do?:
#prod = Spree::Product.find(row["id"])
#var = Spree::Variant.find_by(product_id: #prod.id)
I presume you don't have several entries with one ID. And your not using the objects that you retrieved in those two lines, so simply write the method like this:
def import_update
require 'csv'
file = params[:file]
params = ["name","meta_description","shipping_category_id","description","meta_keywords","tax_category_id","available_on","deleted_at","promotionable","meta_title","featured","supplier_id"]
CSV.foreach(file.path, headers: true) do |row|
hash = {}
params.each do |param|
if row[param]
hash[param] = row[param]
end
end
Spree::Product.find(row["id"]).update_all(hash)
end
end

Related

How do I avoid calling ".clone()" on same String in match multiple times?

Background:
I have some code (Rust) that finds (Regex) matches and assigns the found values to fields in a struct named Article (where all fields are of type String):
pub struct Article {
// user facing data
title: String,
category: String,
subcategory: String,
genre: String,
published: String,
estimated_read_time: String,
description: String,
tags: String,
keywords: String,
image: String,
artwork_credit: String,
// meta data
metas: String,
// location
path: String,
slug: String,
// file data
content: String
}
A regular expression ("//\- define (.*?): (.*?)\n") is used to extract comments from the article's template that define data for that article:
// iterate through HTML property pattern matches
for capture in re_define.captures_iter(&file_content as &str) {
// remove the declaration from the the HTML output
article_content = article_content.replace(&capture[0].to_string(), "");
// get the property value
let property_value: &String = &capture[2].to_string();
// determine what field to assign the property to and assign it
match capture[1].to_lowercase().as_str() {
"title" => article.title = property_value.clone(),
"category" => article.category = property_value.clone(),
"subcategory" => article.subcategory = property_value.clone(),
"genre" => article.genre = property_value.clone(),
"published" => article.published = property_value.clone(),
"estimated_read_time" => article.estimated_read_time = property_value.clone(),
"description" => article.description = property_value.clone(),
"tags" => article.tags = property_value.clone(),
"keywords" => article.keywords = property_value.clone(),
"image" => article.image = property_value.clone(),
unknown_property # _ => {
println!("Ignoring unknown property: {}", &unknown_property);
}
}
}
Note: article is an instance of Article.
Issue:
The code works but what I'm concerned about the following part:
"title" => article.title = property_value.clone(),
"category" => article.category = property_value.clone(),
"subcategory" => article.subcategory = property_value.clone(),
"genre" => article.genre = property_value.clone(),
"published" => article.published = property_value.clone(),
"estimated_read_time" => article.estimated_read_time = property_value.clone(),
"description" => article.description = property_value.clone(),
"tags" => article.tags = property_value.clone(),
"keywords" => article.keywords = property_value.clone(),
"image" => article.image = property_value.clone(),
It calls .clone() on the same String (property_value) for every match (10 matches per article template), for every article template (a couple dozen templates in total), and I don't think it's the most efficient way to do it.
Note: I'm not sure if match is cloning for non-matches.
What I tried:
I tried referencing the property_value String, but I got an error for each reference.
Error from IDE (VS Code):
mismatched types
expected struct `std::string::String`, found `&&std::string::String`
expected due to the type of this binding
try using a conversion method: `(`, `).to_string()`
Error from cargo check:
error[E0308]: mismatched types
--> src/article.rs:84:38
|
84 | "image" => article.image = &property_value,
| ------------- ^^^^^^^^^^^^^^^ expected struct `std::string::String`, found `&&std::string::String`
| |
| expected due to the type of this binding
|
help: try using a conversion method
|
84 | "image" => article.image = (&property_value).to_string(),
| + +++++++++++++
I did try using .to_string(), but I'm not sure if converting a String to the same type is the most efficient to do it either.
Question:
How do I avoid calling .clone() on property_value so many times?
Going by the types, you should just be able to drop the borrow in property_value and then you don't need the .clone()s.
let property_value: &String = &capture[2].to_string();
// change to
let property_value: String = capture[2].to_string();
// or just simply
let property_value = capture[2].to_string();
I'm assuming this was added as capture[2] returns a str (non-sized type) which would require the & but with to_string() it converts to the owned type String which is fine on it's own. This wont have any performance effect as to_string() copies anyway.

what will be a better approach to StreamData when one has 2 maps?

The following property test is working fine, however, I think there should be a better and more efficient way of implementing this.
params in the following property will be something like this:
%{
"project_id" => "%&!XX!hLCfsS-dO_<fy?kpi4y=AEumQ$Xn:#.7Fl TnH~k>ZLB[q",
"task_id" => [
%{"asset_id" => 10, "tasks" => []},
%{"asset_id" => 10, "tasks" => []}
]
}
Property Testing:
property "bad project value" do
[user, project] = prepare()
user_gen = constant(%{id: user.id})
project_gen = constant("project_id")
|> map_of(Factory.my_terms, length: 1)
tasks = constant(%{"asset_id" => 10, "tasks" => []})
|> list_of(length: 2)
tasks_gen = constant("task_id")
|> map_of(tasks, length: 1)
check all project <- project_gen, task <- tasks_gen , user <- user_gen do
params = Map.merge(project, task)
res = ProjectTask.Save.save(params, user)
assert res == {:error, :not_found}
end
Factory.my_terms is the following:
def my_terms() do
one_of([string(:alphanumeric), string(:ascii), atom(:alphanumeric), integer(), binary()])
end
UPDATE
property "bad project value" do
[user, project] = prepare()
project_gen = constant("project_id")
|> map_of(Factory.my_terms, length: 1)
tasks = List.duplicate(%{"asset_id" => 10, "tasks" => []}, 2)
tasks = %{"tasks" => tasks}
check all project <- project_gen do
params = Map.merge(project, tasks)
res = ProjectTask.Save.save(params, %{id: user.id})
assert res == {:error, :not_found}
end
end

Request-URI Too Long in REDMINE TIMESHEET PLUGIN

I am getting in redmine Request-URI Too Long
The requested URL's length exceeds the capacity limit for this server. whenever I try to select csv in timesheet plugin to export the timesheet report.
How do i solve this please tell me
The problem is the method. You are trying to retrieve too many parameters in the url and Apache (or any other like this one) have a limit of 2000 characters by default. In my case I didnt have access to the Apache server so changing the .conf file was not an option.
Looking into the forks of the repository I found someone who has already solved this issue. Here is a link to SashaH's pull request.
This pull request is fairly new so it's not committed yet.
Just change the code as indicated and the plugin should work as you want:
app/helpers/timesheet_helper.rb
:timesheet => timesheet.to_param)
end
- def link_to_csv_export(timesheet)
- link_to('CSV',
- {
- :controller => 'timesheet',
- :action => 'report',
- :format => 'csv',
- :timesheet => timesheet.to_param
- },
- :method => 'post',
- :class => 'icon icon-timesheet')
+ def form_for_csv_export(timesheet)
+ params_like_decode_url = CGI.unescape({:timesheet => timesheet.to_param}.to_query)
+ inputs = ""
+ form = form_tag :controller => 'timesheet', :action => 'report', :format => 'csv' do
+ params_like_decode_url.split("&").each do |param|
+ param_arr = param.split("=")
+ inputs << hidden_field_tag(param_arr.first, param_arr.last, :id => "")
+ end
+ inputs << submit_tag("CSV")
+ inputs.html_safe
+ end
+ form.html_safe
end
def toggle_arrows(element, js_function)
app/models/timesheet.rb
def to_csv
out = "";
+
+ handle_time_entries = {}
+ time_entries.each do |k,v|
+ if k.is_a? String
+ handle_time_entries[k] = v
+ next;
+ end
+ handle_time_entries[k.name] = v
+ end
+
+ time_entries = handle_time_entries
FCSV.generate(out, :encoding => 'u', :force_quotes => true) do |csv|
csv << csv_header
## -314,7 +325,7 ## def time_entries_for_user(user, options={})
return TimeEntry.includes(self.includes).
where(self.conditions([user], extra_conditions)).
- order('spent_on ASC')
+ order('spent_on ASC').references(self.includes)
end
def fetch_time_entries_by_project
app/views/timesheet/report.html.erb
<div class="contextual">
- <%= link_to_csv_export(#timesheet) %>
+ <%= form_for_csv_export(#timesheet) %>
<%= permalink_to_timesheet(#timesheet) %>
</div>
init.rb
require 'redmine'
## Taken from lib/redmine.rb
-#if RUBY_VERSION < '1.9'
-# require 'faster_csv'
-#else
-# require 'csv'
-# FCSV = CSV
-#end
+if RUBY_VERSION < '1.9'
+ require 'faster_csv'
+else
+ require 'csv'
+ FCSV = CSV
+end
if Rails::VERSION::MAJOR < 3
require 'dispatcher'

Drupal services endpoint returns 404 : Could not find resource retrieve

I followed this tutorial :
http://pingv.com/blog/an-introduction-drupal-7-restful-services
and seems everyone have the same problem as mine in the comments.
I made a rest service with drupal services module :
Server = REST
path = api/mohtadoon
mohtadoon_api.module file
<?php
/**
* Implements of hook_services_resources().
*/
function mohtadoon_api_services_resources() {
$api = array(
'mohtadoon' => array(
'operations' => array(
'retrieve' => array(
'help' => 'Retrieves mohtadoon data',
'callback' => 'mohtadoon_api_stories_retrieve',
'file' => array('file' => 'inc', 'module' => 'mohtadoon_api','name' => 'resources/mohtadoon_api'),
'access arguments' => array('access content'),
),
),
),
);
return $api;
}
mohtadoon_api.inc file in resources/mohtadoon_api path
<?php
function mohtadoon_api_stories_retrieve() {
return mohtadoon_api_find_stories();
}
function mohtadoon_api_find_stories() {
// Compose query
$query = db_select('node', 'n');
$query->join('node_revision', 'v', '(n.nid = v.nid) AND (n.vid = v.vid)');
$query->join('users', 'u', 'n.uid = u.uid');
$query->join('field_data_body', 'b', '((b.entity_type = \'node\') AND (b.entity_id = n.nid) AND (b.revision_id = n.vid))');
$query->fields('v', array('timestamp', 'title'));
$query->addField('u', 'name', 'author');
$query->addField('b', 'body_value', 'content');
$query->condition('n.type', 'stories', '=');
$items = $query->execute()->fetchAll();
return $items;
}
?>
when I access the path
http://localhost/mohtadoon01/?q=api/mohtadoon/retrieve
where mohtadoon01 is project path AND ?q= because
the request result is 404 Not found: Could not find resource retrieve.
why is this happens && how to debug something like this ... I didn't deal with drupal before and want to make only one get web service.
You likely need to url encode your string:
http://localhost/mohtadoon01/?q=api%2Fmohtadoon%2Fretrieve
Can't promise this will work though, depending on your drupal configuration.
Slashes are allowed in query string, as per RFC: http://ietf.org/rfc/rfc3986.txt, however many services out of the box do not: you may need to enable AllowEncodedSlashes.
I encountered exactly the same thing using Services 7.x-3.7. To understand the issue, I looked through the following file:
services/servers/rest_server/includes/RESTServer.inc
Given the definition of your service, the code exercised by GET requests for your resource should be:
protected function resolveController($resource, &$operation) {
...
if ( $request_method == 'GET'
&& $canon_path_count >= 1
&& isset($resource['operations']['retrieve'])
&& $this->checkNumberOfArguments($canon_path_count, $resource['operations']['retrieve'])
&& !empty($canonical_path_array[0])
) {
$operation_type = 'operations';
$operation = 'retrieve';
}
...
}
If we now take a look at the code for $this->checkNumberOfArguments():
// We can see from the snippet above that $args_number = $canon_path_count and hence that
// $args_number is always greater than 0
protected function checkNumberOfArguments($args_number, $resource_operation, $required_args = 0) {
$not_required_args = 0;
if (isset($resource_operation['args'])) {
foreach ($resource_operation['args'] as $argument) {
if (isset($argument['source']) && is_array($argument['source']) && isset($argument['source']['path'])) {
if (!empty($argument['optional'])) {
$not_required_args++;
}
else {
$required_args++;
}
}
}
}
// This is where we fall down; Since the service definition does not include any args,
// both $required_args and $not_required_args will equal zero when we get here. Not a problem
// for the first condition (1 >= 0), but clearly the second condition (1 <= 0 + 0) will evaluate
// to false and hence the argument count will not be accepted. As a result, the services module
// does not accept this controller and reports this as '404 not found'
return $args_number >= $required_args && $args_number <= $required_args + $not_required_args;
}
Try adding an argument to your service definition like this:
<?php
/**
* Implements of hook_services_resources().
*/
function mohtadoon_api_services_resources() {
$api = array(
'mohtadoon' => array(
'operations' => array(
'retrieve' => array(
'help' => 'Retrieves mohtadoon data',
'callback' => 'mohtadoon_api_stories_retrieve',
'file' => array('file' => 'inc', 'module' => 'mohtadoon_api','name' => 'resources/mohtadoon_api'),
'access arguments' => array('access content'),
'arg' => array(
array(
'name' => 'entity',
'type' => 'string',
'description' => 'Entity to operate on',
'source' => array('path' => '0'),
'optional' => TRUE,
'default' => '0',
),
),
),
),
),
);
return $api;
}
EDIT:
I think what is confusing people reading the blog post that you linked to (and I was one of those!) is that the URL given as the accessor for the service includes as its final parameter the name of the method that it was intended to invoke ('retrieve'). You could replace 'retrieve' with pretty much anything and the service should still respond (e.g. '/api/blog/pink-rabbit' or, in your case, 'api/mohtadoon/pink-rabbit'). The web service definitions themselves do not indicate what value of parameters can be passed to the endpoint. What counts is what HTTP method is used to access the service and how many parameters are passed to the endpoint (zero or more). Some types of operation require at least a certain number of parameters (e.g. 'retrieve' operations require at least one parameter to identify the specific thing that you want to retrieve).

ZF2 - set selected value on Select Element

I've a problem with dropdown list with Zend Framework 2 & Doctrine.
I would put the "selected" attribute on my dropdown list but all options pass to selected
My code :
Controller :
public function editAction()
{
// get error message during addAction
$this->layout()->setVariable("messageError", $this->flashMessenger()->getErrorMessages());
$auth = $this->getAuthService();
if ($auth->hasIdentity()){
$builder = new AnnotationBuilder();
// Get id of StaticContent
$id = (int)$this->getEvent()->getRouteMatch()->getParam('id');
if (!$id) {
$this->flashMessenger()->addErrorMessage("Aucun plan choisi !");
return $this->redirect()->toRoute('admin/plans');
}
$plan = $this->getEntityManager()->getRepository("Admin\Entity\Plan")->find((int)$id);
$form = $builder->createForm($plan);
// Find options for Localite list (<select>)
$localites = $this->getEntityManager()->getRepository("Admin\Entity\Localite")->getArrayOfAll();
$form->get('localiteid')->setValueOptions($localites);
$form->get('localiteid')->setValue("{$plan->getLocaliteid()->getId()}");
// Find options for TypePlan list (<select>)
$typesPlan = $this->getEntityManager()->getRepository("Admin\Entity\TypePlan")->getArrayOfAll();
$form->get('typeid')->setValueOptions($typesPlan);
$form->get('typeid')->setValue("{$plan->getTypeid()->getId()}");
// Options for Statut list (<select>)
$form->get('statut')->setValueOptions(array('projet'=>'Projet', 'valide'=>'Validé'));
$form->get('statut')->setValue($plan->getStatut());
$form->setBindOnValidate(false);
$form->bind($plan);
$form->add(array(
'name' => 'submit',
'attributes' => array(
'type' => 'submit',
'value' => 'Modifier',
'id' => 'submitbutton',
'class' => "btn btn-primary"
),
));
$request = $this->getRequest();
if ($request->isPost()) {
[...]
}
}
With
$localites = $this->getEntityManager()->getRepository("Admin\Entity\Localite")->getArrayOfAll();
$form->get('localiteid')->setValueOptions($localites);
i populate my dropdown correctly, normally with
$form->get('localiteid')->setValue("{$plan->getLocaliteid()->getId()}");
just set "selected" on option defined by :
$plan->getLocaliteid()->getId()
So why all options are selected in my dropdown ?!
Information : It's the same for typeId but no Statut
It's probably not working because of the curly braces. According to the PHP documentation
Using single curly braces ({}) will not work for accessing the return values of functions or methods or the values of class constants or static class variables.
This is also unnecessary when using setValue. ZF2 will convert it to a string when formatting it in the view.
When you create the arrays to pass to setValueOptions() you should make it an associative array of arrays with the following values:
$form->get('select')->setValueOptions(array(
'field' => array(
'value' => 'value_of_the_option',
'label' => 'what is displayed',
'selected' => true,
),
));
Which ever of the fields has the selected option set to true will be the default selection in the form element.
Personally i don't know if getArrayOfAll() such function exists, i assume that you are correctly passing array to FORM,
I think you should be doing something like this to set value.
$form->get('localiteid')->setValue($plan->getLocaliteid()->getId());
But Since you are populating DROP down i guess this approach will not work best with Drop Down. You need to do something like this
$form->get('localiteid')->setAttributes(array('value'=>$plan->getLocaliteid()->getId(),'selected'=>true));
I've found a bug ?!
$plan = $this->getEntityManager()->getRepository("Admin\Entity\Plan")->find((int)$id);
$idLocalite = 18;//(int)$plan->getLocaliteid()->getId();
$idTypePlan = 2;//(int)$plan->getTypeid()->getId();
When i'm using $plan->getLocaliteid()->getId(); or $plan->getTypeid()->getId() to pass parameter into Repository method getArrayOfAll($idLocalite)
LocaliteRepository.php :
class LocaliteRepository extends EntityRepository {
public function getArrayOfAll($currentLocaliteId) {
$result = $this->_em->createQuery("SELECT l.nom, l.localiteid FROM Admin\Entity\Localite l ORDER BY l.nom")->getArrayResult();
$localite = array();
foreach($result as $loc) {
if ($currentLocaliteId == $loc['localiteid']) {
$localite[$loc['localiteid']] = array(
'value' => $loc['localiteid'],
'label' => $loc['nom'],
'selected' => true,
);
} else {
$localite[$loc['localiteid']] = array(
'value' => $loc['localiteid'],
'label' => $loc['nom'],
'selected' => false
);
//$localite[$loc['localiteid']] = $loc['nom'];
}
}
return $localite;
}
}
So, if i'm using $idLocalite = 18 instead of $idLocalite = (int)$plan->getLocaliteid()->getId() only wanted option are selected. Why ?!