rails include with array of id on condition - ruby-on-rails

I tried to find with array of value using where condition and includes.
But gettting some error..
the below works well and return beneficiary with user included
Beneficiary.includes(:user).where("beneficiaries.id = ?",304)
but when i try with array of ID i'm getting some error
Beneficiary.includes(:caterer_info).where("beneficiaries.id = ?",[304,305])
ActiveRecord::StatementInvalid: Mysql::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '304,305)'

Try the following.
Beneficiary.includes(:caterer_info).where({beneficiaries: {id: [304,305]}})

Why dont you try with where method instead of find_all_by_id
Beneficiary.includes(:caterer_info).where('beneficiaries.id IN (?)', [304,305])

found the answer on my own
Beneficiary.includes(:user).where("beneficiaries.id IN (?)",ids)
Thanks

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

ActiveRecord update error - illegal zero-length identifier

I'm running simple Rails + ActiveRecord program, where I want to take records from the database, where column "transfered_at" is null, and update it with the current time.
orders_ora = Orders.where(transfered_at: nil)
orders_ora.each do |order_ora|
puts order_ora.name
order_ora.update(transfered_at: Time.now)
end
However, it does not allow me to do that. Here is the error that I'm getting:
OCIError: ORA-01741: illegal zero-length identifier: UPDATE
"ORDERS" SET "TRANSFERED_AT" = :a1 WHERE
"ORDERS"."" IS NULL (ActiveRecord::StatementInvalid)
What am I missing?
Edit: I need to use this inside the loop because I'm doing other calculations inside it. And time format does not seems to be the problem, because I'm trying to update another column which type is "number", and I'm getting the same error.
If I try to do it like this:
order_ora.inspection_id = 333
order_ora.save
it also gives the same error as before.
Why do you loop through the results? You can do it in a single query:
Orders.where(transfered_at: nil).update(transfered_at: Time.now)
What could be a problem is that the Time.now is not in the correct format for your table? Use strftime in that case:
Orders.where(transfered_at: nil).update(transfered_at: Time.now.strftime('%H:%M') )
I found answer to this myself, it was not related to the code.
The problem was that my table did not have a PK, and it looks like ActiveRecords uses it to generate SQL statements.

Where query with Time.now

I want to achieve the following:
Model.where("asdasd = ? AND to <= ?", nil, Time.now).each do |model|
I get the following error:
ActiveRecord::StatementInvalid: SQLite3::SQLException: near "to": syntax error: SELECT "bla".* FROM "table" WHERE (asdasd = NULL AND to <= '2015-11-09 10:18:14.777643')
I also use the same in another controller, where I get the same error. What would be the correct way to achieve what I want? I am also quite sure that it worked already like that, could there be any other thing which causes this issue?
Thanks!!!
TO is an SQL keyword, and needs to be quoted in a query. the list of SQLite keywords is avaiable in the SQLite documentation.
Other database engines have similar (but not identical) rules and lists of keywords, so if you change from SQLite then check the rules for whatever the new engine is.

active record how do I specify a column after a join?

I'm trying to make an sql query using activerecord and I'm having a hard time specifying a specific column from multiple joined tables.
for instance in sql
select go.id, sequence.name, sequence.id from sequence join (goterms,...) on ...
this is not beautiful sql but my point is that I'm able to specify which .id I want returned
in activerecord I'm doing this:
results = Sequence.joins(:Foreigndb,:Goterm,:Taxa)
.select(:header,:taxaclass, :genus, :interpro_desc,:description,:dbname,:read_depth, :name)
.distinct
I want to be able to get id from :Goterm but :Taxa and :Foreigndb also use id as a column in the database so i'm getting uninformative errors that I assume stem from this issue when I do the following.
results = Sequence.joins(:Foreigndb,:Goterm,:Taxa)
.select(:header,:taxaclass, :genus, :interpro_desc,:description,:dbname,:read_depth, :name,:id)
.distinct
What is the correct way to just specify that I want Goterm.id?
edit - Here is the error:
ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'Goterm.id' in 'field list'
when I run:
results = Sequence.joins(:Foreigndb,:Goterm,:Taxa).select(:header,:taxaclass,:genus, :interpro_desc,:description,:dbname, :read_depth, :name,'Goterm.id').limit(5).offset(0).dresults = Sequence.joins(:Foreigndb,:Goterm,:Taxa).select(:header,:taxaclass, :genus, :interpro_desc,:description,:dbname, :read_depth, :name,'Goterm.id').limit(5).offset(0).distinct
results = Sequence.joins(:Foreigndb,:Goterm,:Taxa).select(:header,:taxaclass, :genus, :interpro_desc,:description,:dbname,:read_depth, :name, 'sequences.id')
.distinct
It turns out that ilan's answer is correct, however be sure that everything is lower case. I was using 'Goterm.id' to make the selection when it needs to be 'goterm.id'
If anyone else runs into this, I also ran into difficulties grabbing the goterm.id data out of the returned query objects. Each time I called object.id on that return set it would give me something different from what I was expecting. I think the attribute I was expecting was being obscured by something else. To get the data I needed I did the following:
results = Sequence.joins(:Foreigndb,:Goterm,:Taxa).select(:header,:taxaclass, :genus,:interpro_desc,:description,:dbname,:read_depth, :name).distinct
firstRes = results[0]
firstRes.attributes['id']

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

Resources