How does one convert ARRAY_TO_STRING and ARRAY_AGG into arel? - ruby-on-rails

I have an Arel statement that looks like the following:
vulns.project(vulns[:id],
vulns[:cve_id],
vulns[:severity],
vulns[:published_on],
vulns[:description],
"ARRAY_TO_STRING((ARRAY_AGG(#{releases[:version]} ORDER BY #{releases[:released_on]} DESC))[1:10], ', ')")
.join(releases_vulns)
.on(releases_vulns[:vulnerability_id].eq(vulns[:id]))
The toughest part that I am running into is the array_agg and array_to_string. I've checked arel documentation and I did not see a particular matching method to work out a query like this. Has anyone encountered this problem? I could use some help. Thank You.

The way to convert it is the following:
Arel::Nodes::NamedFunction.new 'array_agg', [expression goes here]
Arel::Nodes::NamedFunction.new 'array_to_string', [array_input, Arel::Nodes::Quoted.new(',')]

Related

Sql injection from brakeman for Order by field in rails

Rails version: 5.1.7
Getting Brakeman vulnerability warning for order by field with where clause query in rails
Can, anyone help me to resolve this issue?
Thanks in advance
Query for your reference:
DropdownValue.where(:dropdown_id => PreferenceValue.find(params[:id]).preference.dropdown_id).order("field(id, #{PreferenceValue.find(params[:id]).dropdown_value_ids.join(",")})")
With ActiveRecord sanitize_sql_for_order, i fixed the brakeman sql injection warning
DropdownValue.where(dropdown_id: #preference_value.preference.dropdown_id).order(ActiveRecord::Base.send(:sanitize_sql_for_order, "field(id, #{#preference_value.dropdown_value_ids.join(',')})" ))
I was getting that when using .order("field(id, ...)
Problem
I was trying this inside a model:
scope :order_by_type, lambda {
order_rule = %w[B A C]
order("my_field, #{order_rule}")
}
Then I was getting:
ActiveSupport::DeprecationException: DEPRECATION WARNING: Dangerous query method (method whose arguments are used as raw SQL) called with non-attribute argument(s): "FIELD(my_field, 'B','A','C')"
Solution
I ended up using this neat gem https://github.com/panorama-ed/order_as_specified
It got as simple as
MyModel.order_as_specified(my_field: order_rule)
While not quite a SQL injection vulnerability this whole query is an absolute mess and something that probably should be solved via joining or indirect associations.
You can fix the breakman warning by using a bound parameter instead:
.order("field(id, ?)", PreferenceValue.find(params[:id]).dropdown_value_ids)
It's happening because of this line
"#{PreferenceValue.find(params[:id]).dropdown_value_ids.join(",")}"
do this,
dropdown_ids = PreferenceValue.find(params[:id]).dropdown_value_ids.join(",")
and then in main query
"field(id, #{PreferenceValue.connection.quote(dropdown_ids)})"
connection.quote whitelists the interpolated values.
Give it a try.
Regarding the first answer,
there is no prepared statement in .order() method and this is not a solution.
For my case this one was the working solution:
#skus = skus_scope.preload(...).order(ActiveRecord::Base.send(:sanitize_sql_for_order, "field(id, #{sku_ids.join(',')})"))
You could also go for something cleaner like:
#skus = skus_scope.preload(...).order(sanitize_sql_for_order(["field(id, ?)", sku_ids]))

Using Like in Rails SQL

I got a little problem using the LIKE sentence on rails i know that this next sentence works:
Brand.find(:all, :joins=>[:cars], :conditions=>["brandname LIKE ?","%ford%"])
But it's any way around that I could to something like this:
Brand.find(:all, :joins=>[:cars], :conditions=>["brandname LIKE '%ford%'"])
Its because i already have a function that returns all conditions on a single string, but i require to support search in strings and i don't really how to get it work.
Any help will be appreciated.
I'm not entirely certain that I understand what you're talking about. Are you trying to pass in a variable into the conditions?
I would re-write this query just a tad.
Brand.all.joins(:cars).where("brandname LIKE ?", "%#{some_variable}%")
Of course selecting all can be bad for performance if you get a lot of records so you may want to consider limiting that or paginating the results somehow.
I would recommend the guides. Using an array would be great in this instance
Brand.all.joins(:cars).where("brandname LIKE ?", "%#{params[:brand_search]}%")

Rails: Getting column value from query

Seems like it should be able to look at a simple tutorial or find an aswer with a quick google, but I can't...
codes = PartnerCode.find_by_sql "SELECT * from partner_codes where product = 'SPANMEX' and isused = 'false' limit 1"
I want the column named code, I want just the value. Tried everything what that seems logical. Driving me nuts because everything I find shows an example without referencing the actual values returned
So what is the object returned? Array, hash, ActiveRecord? Thanks in advance.
For Rails 4+ (and a bit earlier I think), use pluck:
Partner.where(conditions).pluck :code
> ["code1", "code2", "code3"]
map is inefficient as it will select all columns first and also won't be able to optimise the query.
You need this one
Partner.where( conditions ).map(&:code)
is shorthand for
Partner.where( conditions ).map{|p| p.code}
PS
if you are often run into such case you will like this gem valium by ernie
it gives you pretty way to get values without instantiating activerecord object like
Partner.where( conditions ).value_of :code
UPDATED:
if you need access some attribute and after that update record
save instance first in some variable:
instance=Partner.where( conditions ).first
then you may access attributes like instance.code and update some attribute
instance.update_attribute || instance.update_attributes
check documentation at api.rubyonrails.org for details

Like and where condition in ruby

What is the syntax for like in Ruby on Rails? This is something I'm trying to do:
I am trying to find all the last name from table which starts with egm so something like %egm%. I know how to do using find_by_sql but just curious to know the Ruby way.
s = Person.find_by_last_name('nan%')
Person.where('name LIKE ?', '%egm%').all
l_name_var = "nan"
Person.where("people.last_name LIKE :l_name", {:l_name => "#{l_name_var}%"})
or in your case
l_name_var = "egm"
Person.where("people.last_name LIKE :l_name", {:l_name => "%#{l_name_var}%"})
To expand a bit, the find_by_X methods use the = operator, so you wouldn't want to use them for a like condition. The "Rails" way involves using a bit of SQL inside of the where method as shown in the other answers. The same would apply if you're trying to sort your results using the order method.

Rails 3 - Need help understanding how to QUERY with a WHERE IN (XXXXX)

I want to build a rails query like the following. And would like to learn how so I can do it again on my own.
Pseudo Code:
#usersprojects = ?? Do I get record or just objects here? not sure?
SELECT *
FROM audit_log
WHERE project_id IN (#usersprojects)
IN the where IN () do I some how tell Rails to use the record.id?
thank you so much for helping me learn this. I want to Rails!
#kchau's answer was close, but you need to map out the project_id's from those records, like so:
AuditLogs.find(#userprojects.map(&:project_id))
So, if #usersprojects contained the User's Projects that you're trying to find audit logs for, you would do a query like:
logs = AuditLogs.find(#userprojects)
See the Rails guide for reference.

Resources