Rails - String concatenation issue while processing an array - ruby-on-rails

I am trying to process the results of an array into a string to pass for a search. I want to build a string from the array that would look something like
("categories.name like '%Forms%' or categories.name like '%Apples%'")
serialize :category, JSON
if category.count > 1 && category.index != 0
$search_global.category.each do |cat_name|
cat_name.slice '" '
# cat_name
$array_count = $array_count + 1
if cat_name != ''
$inside_count = $inside_count +1
$cat_name_2 = "categories.name like %" + $cat_name_2 + cat_name + "% or " + $inside_count.to_s
end
end
end
If I select one item, it works fine as in
categories.name like %Forms% or 1
Please note that I am including the inside count just to get a better idea of what is happening.
The problem I have is when I select 2 or more items. categories.name like % is repeated twice and then the array items or listed as in
categories.name like %categories.name like %Calendar% or 1Forms% or 2
I can't seem to figure out why the concatenation isn't working as I expected.

$cat_name_2 = "categories.name like %" + $cat_name_2 + cat_name + "% or " + $inside_count.to_s
Your are using $cat_name_2 as the asignee as well as inside the assignment statement.

Related

How to pass multiple OR and AND condition in Activate Record in Rails as a string

I'm new in Ruby on rails and I would like to fetch records based on a condition, and I'm passing the condition in a string format. Moreover, I will pass the query in multiple OR and AND conditions. However, right now, I'm stuck that how to pass the query in string format in rails
I have attached the screenshot
#data= CustomAttribute.includes(:custom_attribute_values).where(id: 18, company_id: current_user.company_id).first
The above line executed successfully and gave the output
<CustomAttribute id: 18, data_type: "string", label: "Marital status", code: "marital_status", entity_type: "member", company_id: 1, created_at: "2021-03-10 10:16:15", updated_at: "2021-03-10 10:16:27", is_active: true, is_default: false, rank: nil, is_identifier: false>
but when I executed the below line it gave me the error that
#data.custom_attribute_values.where("\""+"value_string"+"\""+"="+"\""+'Single'+"\"").size
ERROR: column "Single" does not exist
the Single is the value which I would like to count
Here is my code for the dynamic query creation
logical_operator = 'OR'
#custom_attribute = CustomAttribute.includes(:custom_attribute_values).where(id: custom_attribute_ids, company_id: current_user.company_id)
query=""
#custom_attribute.each_with_index do |attribute_object, index|
filter_object= filter_params[:filters].find {|x| x['custom_attribute_id']==attribute_object['id']}
if filter_object.present?
query += "("+ '"' +'value_'+attribute_object.data_type + '"' + ' ' + filter_object['operator'] + ' ' + "'" + filter_object['value'].to_s + "'"+ ")"
end
if index != #custom_attribute.length-1
query+=' '+logical_operator+' '
end
if index == #custom_attribute.length-1
query="'" + " ( " + query + " ) " + "'"
end
end
byebug
puts(#custom_attribute.first.custom_attribute_values.where(query).size)
Any time you're doing a lot of escaping and string addition in Ruby you're doing it wrong. If we clean up how you build your SQL:
"\""+"value_string"+"\""+"="+"\""+'Single'+"\""
things will be clearer. First, put space around your operators for readability:
"\"" + "value_string" + "\"" + "=" + "\"" + 'Single' + "\""
Next, don't use double quotes unless you need them for escape codes (such as \n) or interpolation:
'"' + 'value_string' + '"' + '=' + '"' + 'Single' + '"'
Now we see that we're adding several constant strings so there's no need to add them at all, a single string literal will do:
'"value_string" = "Single"'
Standard SQL uses double quotes for identifiers (such as table and column names) and single quotes for strings. So your query is asking for all rows where the value_string column equals the Single column and there's your error.
You want to use single quotes for the string (and %q(...) to quote the whole thing to avoid adding escapes back in):
#data.custom_attribute_values.where(
%q("value_string" = 'Single')
)
Or better, let ActiveRecord build the query:
# With a positional placeholder:
#data.custom_attribute_values.where('value_string = ?', 'Single')
# Or a named placeholder:
#data.custom_attribute_values.where('value_string = :s', s: 'Single')
# Or most idiomatic:
#data.custom_attribute_values.where(value_string: 'Single')

Zend 2 escaping single-quote

I am using Zend Framework 2 to generate the following escaped single-quote SQL query,
SELECT
`document`.*
FROM
`document`
WHERE
(
`document`.`document_taxon` LIKE '%Men\'s Health %' --escaped quote
AND `document`.`document_source_id` = ' 5 '
AND `document`.`document_published` = ' 1 '
AND `document`.`document_deleted` = ' 0 '
)
ORDER BY
`document_id` DESC
LIMIT 25 OFFSET 0
But I am getting this instead,
SELECT
`document`.*
FROM
`document`
WHERE
(
`document`.`document_taxon` LIKE '%Men's Health%'
AND `document`.`document_source_id` = ' 5 '
AND `document`.`document_published` = ' 1 '
AND `document`.`document_deleted` = ' 0 '
)
ORDER BY
`document_id` DESC
LIMIT 25 OFFSET 0
And here is my code
class DocumentTable extends TableGateway
{
....
$select=$this->getSql()->select();
$select->columns(array('*'));
$select->where
->NEST
->like('document_taxon', '%' . $label . '%')
->and
->equalTo('document_source_id', $sourceId)
->and
->equalTo('document_published', true)
->and
->equalTo('document_deleted', 0)
->UNNEST;
$select->order('document_id DESC');
$select->limit($limit);
$select->offset($offset);
...
}
I tried,
$this->getAdapter()->getPlatform()->quoteValue($string)
\Zend\Db\Sql\Expression("%". $label . "%")
str_replace("'", "\'", $label)
But I didn’t have much luck. I welcome any suggestion to solve this issue.
I worked it out. I was passing a normalized “label” value instead of the raw value. The above code snippet works fine.

Creating custom rails route: undefined method `+#' for "10":String

I am making a custom rails route as:
match '/setFavoriteRestaurant/:user_id/:restaurant_id/:campaignSetFav_id/:metro_id/:time_period', to: 'requests#setFavoriteRestaurant', via: 'get'
with controller action:
def setFavoriteRestaurant
setFavorite = "INSERT INTO androidchatterdatabase.users_favorite_restaurants(usersId,restaurantId,campaignIdSetFav,metroId,timePeriod,favoritedDt)
VALUES(" + params[:user_id].to_s + ","
+ params[:restaurant_id].to_s + ","
+ params[:campaignSetFav_id].to_s + ","
+ params[:metro_id].to_s + ","
+ params[:time_period].to_s + ",
NOW());"
ActiveRecord::Base.connection.execute(setFavorite)
end
Yet when testing in the browser with: http://localhost:3000/setFavoriteRestaurant/1/2/3/5/4
it returns an odd error as: undefined method +#' for "2":String
Why is this the case when other methods, setup exactly the same are fine to run?
This has to do with how you broke up the lines. Ruby doesn't know that the VALUES(" + line and the + params[:restaurant_id] are part of the same thing. This is because the VALUES( + line is complete. Move the + to the end of the line so that Ruby will know to expect the next line to be a continuation.
setFavorite = "INSERT INTO androidchatterdatabase.users_favorite_restaurants(usersId,restaurantId,campaignIdSetFav,metroId,timePeriod,favoritedDt)" +
"VALUES(" + params[:user_id].to_s + "," +
params[:restaurant_id].to_s + "," +
params[:campaignSetFav_id].to_s + "," +
params[:metro_id].to_s + "," +
params[:time_period].to_s + ",NOW());"
Also, note that I moved some other things around to avoid new lines and extra spaces.
I'm not sure why you prefer raw SQL here, but you should consider going through Rails. Seems like you're opening yourself up to SQL injection. At the very least, you could have some constraints in the route to match only integers.
Ruby has a couple of ways to quote multi line strings:
1) Here it is with ruby's heredoc syntax:
def some_action
setFavorite = <<-"END_OF_INSERT"
INSERT INTO androidchatterdatabase.users_favorite_restaurants(
usersId,
restaurantId,
campaignIdSetFav,
metroId,
timePeriod,
favoritedDt
)
VALUES(
"#{params[:user_id]}",
"#{params[:restaurant_id]}",
"#{params[:campaignSetFav_id]}",
"#{params[:metro_id]}",
"#{params[:time_period]}",
NOW()
);
END_OF_INSERT
end
Explanation:
setFavorite = <<-"END_OF_INSERT"
- => Terminator does not have to be at the start of the line.
"" => This is a double quoted string--do interpolation.
2) Here it is with %Q{}:
setFavorite = %Q{
INSERT INTO androidchatterdatabase.users_favorite_restaurants(
usersId,
restaurantId,
campaignIdSetFav,
metroId,
timePeriod,
favoritedDt
)
VALUES(
"#{params[:user_id]}",
"#{params[:restaurant_id]}",
"#{params[:campaignSetFav_id]}",
"#{params[:metro_id]}",
"#{params[:time_period]}",
NOW()
);
}
However, your SQL statement is still vulnerable to sql injection attacks. Check your db adapter for how to do parameter substitutions.

Ruby, pluck on hashes

s is hashes of array
relativebase = s.pluck(:base_point).inject(:+) + s.pluck(:distance_point).inject(:+) + s.pluck(:speed_point).inject(:+) + s.pluck(:frequency_point).inject(:+) + s.pluck(:quality_point).inject(:+)
This is calling the database four times which I want to do in one single query. How can i get this.
Something like:
User.select(:a, :b, :c, :d).all.inject([]) { |res, e| res << e.a; res << e.b; res << e.c; res << e.d; res }
Rails 4 supports multiple names in pluck:
relativebase = s.pluck(:base_point,
:distance_point,
:speed_point,
:frequency_point).inject(0) do |sum, (bp, dp, sp, fp)|
sum + bp + dp + sp + fp
end
Actually I personally think that it is probably better to calculate the sum in the database, but I'm not sure how to do that elegantly in rails:
SELECT SUM(base_point + distance_point + speed_point + frequency_point) FROM s

Rails helpers return just strings. How would I have it return HTML?

I am trying to return this in it's predictable HTML way :
'Page Total ' + #total_on_page + tag('br') + 'Total All Pages'.html_safe + #total
But instead it just parses the br/ as plain text. How do I return a working HTML version of br/ ?
Expected Output :
Page Total $123123
Total All Pages $12312312
Actual Output :
Page Total $8,296.42<br />Total All Pages$23,669.73
The .html_safe at the end is applying only to the last string, not the overall string. You want something more like this:
('Page Total ' + #total_on_page + tag('br') + 'Total All Pages' + #total).html_safe

Resources