How to pass multiple OR and AND condition in Activate Record in Rails as a string - ruby-on-rails

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')

Related

Google Ads Scripts AWQL "CONTAINS_ANY" operator doesn't work

I'm trying to extract Search queries by certain rules and I need to get Queries that contain one of the given strings:
" WHERE " +
" Impressions > " + IMPRESSIONS_THRESHOLD +
" AND AverageCpc > " + AVERAGE_CPC_THRESHOLD +
" AND Query CONTAINS_ANY ['for sale in', 'buy'] " +
" DURING YESTERDAY ");
But I'm getting error message (tryed different variations):
One of the conditions in the query is invalid. (file Code.gs, line 19)
Although it seems like I do everything according to Formal Grammar:
String -> StringSingleQ | StringDoubleQ
StringSingleQ -> '(char)'
StringDoubleQ -> "(char)"
StringList -> [ String (, String)* ]
If I do just 1 string it works fine:
" WHERE " +
" Impressions > " + IMPRESSIONS_THRESHOLD +
" AND AverageCpc > " + AVERAGE_CPC_THRESHOLD +
" AND Query CONTAINS 'for sale in' " +
" DURING YESTERDAY ");
IIRC, the CONTAINS_ANY operator only works when you are filtering on labels. I'm not sure if this constraint is actually documented, but this article seems to at least imply it.

How can I perfom an update with jena fuseki?

I've wrote this query that normally works
String query2 = "PREFIX publ: <http://www.ps7-wia2.com/publications/>\n" +
"PREFIX pub: <http://www.ps7-wia2.com/publications#>" +
"DELETE { publ: " + id + " pub:like ?o }\n" +
"INSERT { publ: " + id + " pub:like " + nbLikes + " }\n" +
"WHERE {publ:" + id + " pub:like ?o .}\n";
RDFConnection conn2 = RDFConnectionFactory.connect(DATABASE);
QueryExecution qExec2 = conn2.query(query2) ;
conn2.close();
qExec2.close();
And when I execute I encounter this error
org.apache.jena.query.QueryParseException: Encountered " "delete" "DELETE "" at line 2, column 52.
Was expecting one of:
"base" ...
"prefix" ...
"select" ...
"json" ...
"describe" ...
"construct" ...
"ask" ...
```
In SPARQL, query and update are parsed separately; they are separate languages which use many of the same elements but have different syntax for their functionality ("SELECT" vs "INSERT" etc).
Use update(...).

Creating a checksum for passed in parameters in Ruby

I am creating a checksum for my payment gateway. The checksum should be in this format:
key|txnid|amount|productinfo|firstname|email|||||||||||salt
I need to leave 11 pipes between the email and the salt.
In my controller I created a method:
require 'digest/sha2'
def getChecksum(key, txnid, amount, productinfo, firstname, email, phone, surl, furl)
String str = key + '|' + txnid + '|' + amount + '|' + productinfo + '|' + firstname + '|' + email + '|' + phone + '|' + surl + '|' + furl+ '|'+ '|'+ '|'+ '|'+ '|'+ '|'+ '|'+ '|' + 'salt'
Digest::SHA512.hexdigest( str )
end
I called this method in my controller:
hash: getChecksum(
key: 'key_value',
txnid: '4',
amount: '2000',
productinfo: 'first sales',
firstname: 'John',
email: 'johndepp#gmail.com',
phone: '123456789',
surl: 'http://someurl.io',
furl: 'http://someurl.io')
But now I am getting a "wrong number of arguments" error:
wrong number of arguments (1 for 9)
def getChecksum( key, txnid,
amount, productinfo, firstname, email, phone, surl, furl)
I think all the parameters are considered as a single one. Can someone tell me what I am doing wrong here?
You are sending a single hash as the parameter, instead you need to send the values only (without keys). Also no need to declare the type String str, you should review your Ruby fundamentals, I'm guessing you come from another language.
# You are calling this
getChecksum(key: 'key_value', txnid: '4', ...)
# which syntactically equals this, a single hash as a parameter
getChecksum({key: 'key_value', txnid: '4', ...})
# Instead, send the values alone
getChecksum('key_value', '4', ...)
Let's look at how you're writing your code and see if we can make it more Ruby-like and hopefully more production-worthy.
You wrote this:
def getChecksum(key, txnid, amount, productinfo, firstname, email, phone, surl, furl)
String str = key + '|' + txnid + '|' + amount + '|' + productinfo + '|' + firstname + '|' + email + '|' + phone + '|' + surl + '|' + furl+ '|'+ '|'+ '|'+ '|'+ '|'+ '|'+ '|'+ '|' + 'salt'
Digest::SHA512.hexdigest( str )
end
First, ick.
Methods and variables in Ruby are snake_case, not camelCase. ItsAReadabilityThing.
We don't define variables using String str =.... Ruby can figure out what type of variable it is 99.99% of the time, so str =... is sufficient.
Think about how you're using fixed-strings and values. '|' is your separator, so define it as such:
SEPARATOR = '|'
And you need eleven of them as a divider, so define that:
DIVIDER = SEPARATOR * 11
I'd write the code more like this:
require 'digest/sha2'
SEPARATOR = '|'
DIVIDER = SEPARATOR * 11 # => "|||||||||||"
def checksum_1(key, txnid, amount, productinfo, firstname, email, phone, surl, furl)
str = [key, txnid, amount, productinfo, firstname, email, phone, surl, furl].join(SEPARATOR) + DIVIDER + 'salt'
Digest::SHA512.hexdigest(str)
end
But even that can be improved upon.
When we have more than three parameters it's time to refactor and clean up the parameter list. There are many ways to do it, but using a hash is the most common:
def checksum_2(params)
str = params.values_at(
:key, :txnid, :amount, :productinfo, :firstname, :email, :phone, :surl, :furl
).join(SEPARATOR) + DIVIDER + 'salt'
Digest::SHA512.hexdigest( str )
end
Using values_at is a nice way to extract the values of the keys in a hash. They come out in an array in the same order of the keys.
The problem now is that a parameter could be missing and Ruby won't catch it. Named parameters are the new-hotness for dealing with that, but for older Rubies, or to get an idea how it might be done in other languages, we can look at the keys received, then their associated values, and if things don't look good raise an exception rather than return a bogus value.
To make things easier I'm going to use Active Support's blank? method, found in the Core Extensions:
require 'active_support/core_ext/object/blank'
def checksum_3(params)
required_values = [:key, :txnid, :amount, :productinfo, :firstname, :email, :phone, :surl, :furl]
missing_keys = required_values - params.keys
fail ArgumentError, "Missing keys: #{ missing_keys.map{ |k| ":#{ k }" }.join(', ') }" unless missing_keys.empty?
missing_values = required_values.select{ |k| params[k].blank? }
fail ArgumentError, "Missing values for: #{ missing_values.map{ |k| ":#{ k }" }.join(', ') }" unless missing_values.empty?
str = params.values_at(*required_values).join(SEPARATOR) + DIVIDER + 'salt'
Digest::SHA512.hexdigest(str)
end
Here's how the calls to the various versions of the method look, along with the associated checksum that's returned:
c1 = checksum_1('key_value', '4', '2000', 'first sales', 'John', 'johndepp#gmail.com', '123456789', 'http://someurl.io', 'http://someurl.io')
c2 = checksum_2(
key: 'key_value',
txnid: '4',
amount: '2000',
productinfo: 'first sales',
firstname: 'John',
email: 'johndepp#gmail.com',
phone: '123456789',
surl: 'http://someurl.io',
furl: 'http://someurl.io'
)
c3 = checksum_3(
key: 'key_value',
txnid: '4',
amount: '2000',
productinfo: 'first sales',
firstname: 'John',
email: 'johndepp#gmail.com',
phone: '123456789',
surl: 'http://someurl.io',
furl: 'http://someurl.io'
)
c1 # => "fcf4e21c6e711808a6984824f09552dccc5c4378b55720c88b3abd4a1904931b8d883beaef51edec705a9d8b0ccd3ba898a0d4c05f75bd41fa3b90f0df7b5c79"
c2 # => "fcf4e21c6e711808a6984824f09552dccc5c4378b55720c88b3abd4a1904931b8d883beaef51edec705a9d8b0ccd3ba898a0d4c05f75bd41fa3b90f0df7b5c79"
c3 # => "fcf4e21c6e711808a6984824f09552dccc5c4378b55720c88b3abd4a1904931b8d883beaef51edec705a9d8b0ccd3ba898a0d4c05f75bd41fa3b90f0df7b5c79"
While we still have to pass in the same amount of information, using the hash allows us to see what each parameter is being assigned to, resulting in self-documenting code, which is a very important thing for long-term maintenance. Also, the hash doesn't require a specific order of the parameters, making it easier to write the code calling it; I usually know I need certain things but can't remember what order they're in.
That's all my take on how to write this type of code. See "Ruby 2 Keyword Arguments" for a similar write-up on the same topic.
Here's how you would define the method with keyword arguments:
def getChecksum(key:, txnid:, amount:, productinfo:, firstname:, email:, phone:, surl:, furl:)
str = key + '|' + txnid + '|' + amount + '|' + productinfo + '|' + firstname + '|' + email + '|' + phone + '|' + surl + '|' + furl+ '|'+ '|'+ '|'+ '|'+ '|'+ '|'+ '|'+ '|' + 'salt'
Digest::SHA512.hexdigest( str )
end
Then you can call it with a hash like you are currently.
I think this looks a bit cleaner, though:
def get_checksum(key:, txnid:, amount:, productinfo:, firstname:, email:, phone:, surl:, furl:)
str = "#{key}|#{txnid}|#{amount}|#{productinfo}|#{firstname}|#{email}|#{phone}|#{surl}|#{furl}||||||||salt"
Digest::SHA512.hexdigest(str)
end
Or perhaps:
def get_checksum(key:, txnid:, amount:, productinfo:, firstname:, email:, phone:, surl:, furl:)
str = [ key, txnid, amount, productinfo, firstname, email, phone, surl, furl ].join("|")
Digest::SHA512.hexdigest("#{str}||||||||salt")
end
You can learn more about keyword arguments, including how to give keywords default values to make them optional, here: https://robots.thoughtbot.com/ruby-2-keyword-arguments

How to calculate the hash for a payment form?

I'm trying to calculate a hash for a payment form but I get the error:
no implicit conversion of Fixnum into String
so I interpret this that I'm trying to do math calculation on what is text. But how should I correct my code?
The instructions from the payment merchant are:
hash = SHA1(salt + "|" + description + "|" + amount + "|" + currency +
"|" + transaction_type)
So in my controller I have:
def checkout
#organization = Organization.new(organizationnew_params)
if #organization.save
#organization.members.each do |single_member|
single_member.send_activation_email
end
#amount = 100.00
#currency = "EUR"
#description = #organization.id
#transaction_description = "My description"
#transaction_type = "S"
### LINE BELOW HAS THE HASH, WHICH REFERS TO THE PRIVATE METHOD BELOW ###
#hash = hash(#description, #amount, #currency, #transaction_type)
render 'checkout'
else
render 'new_premium'
end
end
private
def hash(description, amount, currency, transaction_type)
#hash = SHA1(SALT + "|" + description + "|" + amount + "|" + currency + "|" + transaction_type)
end
In an initializer I have defined SALT (as well as my merchant_id which is used in the form that is posted to the merchant in the checkout view).
Writing this will be better.
hash = SHA1([salt, description, amount.to_s, currency,transaction_type].join("|"))
You interpreted it wrongly, it's the other way round. You're trying to use a number as a string.
Try to explicitely convert the number in to a string, like so:
#hash = SHA1(SALT + "|" + description + "|" + amount.to_s + "|" + currency + "|" + transaction_type)
As I don't know what all the variables' types are, you might have to add another to_s to a non-string.
The error indicates that you are adding a number to a string, I think the problem is that "amount" is a number which you are adding to a string. you just have to change that:
#hash = SHA1(SALT + "|" + description + "|" + amount.to_s + "|" + currency + "|" + transaction_type)
the :to_s method will convert amount into string. (if there are other numbers just do the same.)
Or you can do this with string interpolation:
#hash = SHA1("#{SALT}|#{description}|#{amount}|#{currency}|#{transaction_type}")

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.

Resources